blob: eea88b7ddb9f0e863fcf4a5560a2a1f146f469e7 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for ALC 260/880/882 codecs
5 *
Kailang Yangdf694da2005-12-05 19:42:22 +01006 * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
7 * PeiSen Hou <pshou@realtek.com.tw>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * Takashi Iwai <tiwai@suse.de>
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01009 * Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * This driver is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This driver is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/init.h>
27#include <linux/delay.h>
28#include <linux/slab.h>
29#include <linux/pci.h>
30#include <sound/core.h>
Kailang Yang9ad0e492010-09-14 23:22:00 +020031#include <sound/jack.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include "hda_codec.h"
33#include "hda_local.h"
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090034#include "hda_beep.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
Kailang Yangccc656c2006-10-17 12:32:26 +020036#define ALC880_FRONT_EVENT 0x01
37#define ALC880_DCVOL_EVENT 0x02
38#define ALC880_HP_EVENT 0x04
39#define ALC880_MIC_EVENT 0x08
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
41/* ALC880 board config type */
42enum {
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 ALC880_3ST,
44 ALC880_3ST_DIG,
45 ALC880_5ST,
46 ALC880_5ST_DIG,
47 ALC880_W810,
Takashi Iwaidfc0ff62005-05-12 14:31:49 +020048 ALC880_Z71V,
Takashi Iwaib6482d42005-06-27 15:32:43 +020049 ALC880_6ST,
Takashi Iwai16ded522005-06-10 19:58:24 +020050 ALC880_6ST_DIG,
51 ALC880_F1734,
52 ALC880_ASUS,
53 ALC880_ASUS_DIG,
54 ALC880_ASUS_W1V,
Kailang Yangdf694da2005-12-05 19:42:22 +010055 ALC880_ASUS_DIG2,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +010056 ALC880_FUJITSU,
Takashi Iwai16ded522005-06-10 19:58:24 +020057 ALC880_UNIWILL_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +020058 ALC880_UNIWILL,
59 ALC880_UNIWILL_P53,
Kailang Yangdf694da2005-12-05 19:42:22 +010060 ALC880_CLEVO,
61 ALC880_TCL_S700,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010062 ALC880_LG,
Takashi Iwaid6815182006-03-23 16:06:23 +010063 ALC880_LG_LW,
Takashi Iwaidf99cd32008-04-25 15:25:04 +020064 ALC880_MEDION_RIM,
Takashi Iwaie9edcee2005-06-13 14:16:38 +020065#ifdef CONFIG_SND_DEBUG
66 ALC880_TEST,
67#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010068 ALC880_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020069 ALC880_MODEL_LAST /* last tag */
70};
71
72/* ALC260 models */
73enum {
74 ALC260_BASIC,
75 ALC260_HP,
Kailang Yang3f878302008-08-26 13:02:23 +020076 ALC260_HP_DC7600,
Kailang Yangdf694da2005-12-05 19:42:22 +010077 ALC260_HP_3013,
78 ALC260_FUJITSU_S702X,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +010079 ALC260_ACER,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020080 ALC260_WILL,
81 ALC260_REPLACER_672V,
Michael Schwingencc959482009-02-22 18:58:45 +010082 ALC260_FAVORIT100,
Jonathan Woithe7cf51e482006-02-09 12:01:26 +010083#ifdef CONFIG_SND_DEBUG
84 ALC260_TEST,
85#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010086 ALC260_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020087 ALC260_MODEL_LAST /* last tag */
Linus Torvalds1da177e2005-04-16 15:20:36 -070088};
89
Kailang Yangdf694da2005-12-05 19:42:22 +010090/* ALC262 models */
91enum {
92 ALC262_BASIC,
Kailang Yangccc656c2006-10-17 12:32:26 +020093 ALC262_HIPPO,
94 ALC262_HIPPO_1,
Takashi Iwai834be882006-03-01 14:16:17 +010095 ALC262_FUJITSU,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020096 ALC262_HP_BPC,
Kailang Yangcd7509a2007-01-26 18:33:17 +010097 ALC262_HP_BPC_D7000_WL,
98 ALC262_HP_BPC_D7000_WF,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010099 ALC262_HP_TC_T5735,
Kailang Yang8c427222008-01-10 13:03:59 +0100100 ALC262_HP_RP5700,
Takashi Iwai304dcaa2006-07-25 14:51:16 +0200101 ALC262_BENQ_ED8,
Kailang Yang272a5272007-05-14 11:00:38 +0200102 ALC262_SONY_ASSAMD,
Kailang Yang83c34212007-07-05 11:43:05 +0200103 ALC262_BENQ_T31,
Tobin Davisf651b502007-10-26 12:40:47 +0200104 ALC262_ULTRA,
Jiang zhe0e31daf2008-03-20 12:12:39 +0100105 ALC262_LENOVO_3000,
Pascal Terjane8f9ae22008-08-04 14:36:05 +0200106 ALC262_NEC,
Kailang Yang4e555fe2008-08-26 13:05:55 +0200107 ALC262_TOSHIBA_S06,
Hiroshi Miura9f99a632008-08-28 16:09:06 +0200108 ALC262_TOSHIBA_RX1,
Tony Vroonba340e82009-02-02 19:01:30 +0000109 ALC262_TYAN,
Kailang Yangdf694da2005-12-05 19:42:22 +0100110 ALC262_AUTO,
111 ALC262_MODEL_LAST /* last tag */
112};
113
Kailang Yanga361d842007-06-05 12:30:55 +0200114/* ALC268 models */
115enum {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +0200116 ALC267_QUANTA_IL1,
Kailang Yanga361d842007-06-05 12:30:55 +0200117 ALC268_3ST,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200118 ALC268_TOSHIBA,
Takashi Iwaid2738092007-08-16 14:59:45 +0200119 ALC268_ACER,
Takashi Iwaic238b4f2008-11-05 14:57:20 +0100120 ALC268_ACER_DMIC,
Kailang Yang8ef355d2008-08-26 13:10:22 +0200121 ALC268_ACER_ASPIRE_ONE,
Takashi Iwai3866f0b2008-01-15 12:37:42 +0100122 ALC268_DELL,
Mirco Tischlerf12462c2008-02-04 12:33:59 +0100123 ALC268_ZEPTO,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +0100124#ifdef CONFIG_SND_DEBUG
125 ALC268_TEST,
126#endif
Kailang Yanga361d842007-06-05 12:30:55 +0200127 ALC268_AUTO,
128 ALC268_MODEL_LAST /* last tag */
129};
130
Kailang Yangf6a92242007-12-13 16:52:54 +0100131/* ALC269 models */
132enum {
133 ALC269_BASIC,
Kailang Yang60db6b52008-08-26 13:13:00 +0200134 ALC269_QUANTA_FL1,
Kailang Yang84898e82010-02-04 14:16:14 +0100135 ALC269_AMIC,
136 ALC269_DMIC,
137 ALC269VB_AMIC,
138 ALC269VB_DMIC,
Takashi Iwai26f5df22008-11-03 17:39:46 +0100139 ALC269_FUJITSU,
Tony Vroon64154832008-11-06 15:08:49 +0000140 ALC269_LIFEBOOK,
Kailang Yangfe3eb0a2010-08-06 10:02:57 +0200141 ALC271_ACER,
Kailang Yangf6a92242007-12-13 16:52:54 +0100142 ALC269_AUTO,
143 ALC269_MODEL_LAST /* last tag */
144};
145
Kailang Yangdf694da2005-12-05 19:42:22 +0100146/* ALC861 models */
147enum {
148 ALC861_3ST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200149 ALC660_3ST,
Kailang Yangdf694da2005-12-05 19:42:22 +0100150 ALC861_3ST_DIG,
151 ALC861_6ST_DIG,
Takashi Iwai22309c32006-08-09 16:57:28 +0200152 ALC861_UNIWILL_M31,
Tobin Davisa53d1ae2006-10-17 12:00:28 +0200153 ALC861_TOSHIBA,
Mariusz Domanski7cdbff92006-10-23 13:42:56 +0200154 ALC861_ASUS,
Takashi Iwai56bb0ca2006-11-22 11:52:52 +0100155 ALC861_ASUS_LAPTOP,
Kailang Yangdf694da2005-12-05 19:42:22 +0100156 ALC861_AUTO,
157 ALC861_MODEL_LAST,
158};
159
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100160/* ALC861-VD models */
161enum {
162 ALC660VD_3ST,
Mike Crash6963f842007-06-25 12:12:51 +0200163 ALC660VD_3ST_DIG,
Takashi Iwai13c94742008-11-05 08:06:08 +0100164 ALC660VD_ASUS_V1S,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100165 ALC861VD_3ST,
166 ALC861VD_3ST_DIG,
167 ALC861VD_6ST_DIG,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200168 ALC861VD_LENOVO,
Kailang Yang272a5272007-05-14 11:00:38 +0200169 ALC861VD_DALLAS,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200170 ALC861VD_HP,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100171 ALC861VD_AUTO,
172 ALC861VD_MODEL_LAST,
173};
174
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200175/* ALC662 models */
176enum {
177 ALC662_3ST_2ch_DIG,
178 ALC662_3ST_6ch_DIG,
179 ALC662_3ST_6ch,
180 ALC662_5ST_DIG,
181 ALC662_LENOVO_101E,
Kailang Yang291702f2007-10-16 14:28:03 +0200182 ALC662_ASUS_EEEPC_P701,
Kailang Yang8c427222008-01-10 13:03:59 +0100183 ALC662_ASUS_EEEPC_EP20,
Kailang Yang6dda9f42008-05-27 12:05:31 +0200184 ALC663_ASUS_M51VA,
185 ALC663_ASUS_G71V,
186 ALC663_ASUS_H13,
187 ALC663_ASUS_G50V,
Kailang Yangf1d4e282008-08-26 14:03:29 +0200188 ALC662_ECS,
189 ALC663_ASUS_MODE1,
190 ALC662_ASUS_MODE2,
191 ALC663_ASUS_MODE3,
192 ALC663_ASUS_MODE4,
193 ALC663_ASUS_MODE5,
194 ALC663_ASUS_MODE6,
Kailang Yangebb83ee2009-12-17 12:23:00 +0100195 ALC663_ASUS_MODE7,
196 ALC663_ASUS_MODE8,
Kailang Yang622e84c2009-04-21 07:39:04 +0200197 ALC272_DELL,
198 ALC272_DELL_ZM1,
Chris Pockelé9541ba12009-05-12 08:08:53 +0200199 ALC272_SAMSUNG_NC10,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200200 ALC662_AUTO,
201 ALC662_MODEL_LAST,
202};
203
Kailang Yangdf694da2005-12-05 19:42:22 +0100204/* ALC882 models */
205enum {
206 ALC882_3ST_DIG,
207 ALC882_6ST_DIG,
Takashi Iwai4b146cb2006-07-28 14:42:36 +0200208 ALC882_ARIMA,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200209 ALC882_W2JC,
Kailang Yang272a5272007-05-14 11:00:38 +0200210 ALC882_TARGA,
211 ALC882_ASUS_A7J,
Takashi Iwai914759b2007-09-06 14:52:04 +0200212 ALC882_ASUS_A7M,
Tobin Davis9102cd12006-12-15 10:02:12 +0100213 ALC885_MACPRO,
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -0800214 ALC885_MBA21,
Takashi Iwai87350ad2007-08-16 18:19:38 +0200215 ALC885_MBP3,
Kacper Szczesniak41d55452009-05-07 12:47:43 +0200216 ALC885_MB5,
Luke Yelaviche458b1f2010-02-12 16:28:29 +1100217 ALC885_MACMINI3,
Nicola Fagnanic54728d2007-07-19 23:28:52 +0200218 ALC885_IMAC24,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -0800219 ALC885_IMAC91,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200220 ALC883_3ST_2ch_DIG,
221 ALC883_3ST_6ch_DIG,
222 ALC883_3ST_6ch,
223 ALC883_6ST_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +0200224 ALC883_TARGA_DIG,
225 ALC883_TARGA_2ch_DIG,
David Heidelberger64a8be72009-06-08 16:15:18 +0200226 ALC883_TARGA_8ch_DIG,
Vladimir Avdoninbab282b92006-08-22 13:31:58 +0200227 ALC883_ACER,
Tobin Davis2880a862007-08-07 11:50:26 +0200228 ALC883_ACER_ASPIRE,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +0800229 ALC888_ACER_ASPIRE_4930G,
Tony Vroond2fd4b02009-06-21 00:40:10 +0100230 ALC888_ACER_ASPIRE_6530G,
Hector Martin3b315d72009-06-02 10:54:19 +0200231 ALC888_ACER_ASPIRE_8930G,
Denis Kuplyakovfc86f952009-08-25 18:15:59 +0200232 ALC888_ACER_ASPIRE_7730G,
Tobin Davisc07584c2006-10-13 12:32:16 +0200233 ALC883_MEDION,
Kailang Yangea1fb292008-08-26 12:58:38 +0200234 ALC883_MEDION_MD2,
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +0200235 ALC883_MEDION_WIM2160,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +0100236 ALC883_LAPTOP_EAPD,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200237 ALC883_LENOVO_101E_2ch,
Kailang Yang272a5272007-05-14 11:00:38 +0200238 ALC883_LENOVO_NB0763,
Kailang Yang189609a2007-08-20 11:31:23 +0200239 ALC888_LENOVO_MS7195_DIG,
Kailang Yange2757d52008-08-26 13:17:46 +0200240 ALC888_LENOVO_SKY,
Kailang Yangea1fb292008-08-26 12:58:38 +0200241 ALC883_HAIER_W66,
Claudio Matsuoka4723c022007-07-13 14:36:19 +0200242 ALC888_3ST_HP,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +0100243 ALC888_6ST_DELL,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +0100244 ALC883_MITAC,
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -0430245 ALC883_CLEVO_M540R,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +0100246 ALC883_CLEVO_M720,
Jiang zhefb97dc62008-03-06 11:07:11 +0100247 ALC883_FUJITSU_PI2515,
Vincent Petryef8ef5f2008-11-23 11:31:41 +0800248 ALC888_FUJITSU_XA3530,
Jiang zhe17bba1b2008-06-04 12:11:07 +0200249 ALC883_3ST_6ch_INTEL,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +0200250 ALC889A_INTEL,
251 ALC889_INTEL,
Kailang Yange2757d52008-08-26 13:17:46 +0200252 ALC888_ASUS_M90V,
253 ALC888_ASUS_EEE1601,
Torben Schulzeb4c41d2009-05-18 15:02:35 +0200254 ALC889A_MB31,
Wu Fengguang3ab90932008-11-17 09:51:09 +0100255 ALC1200_ASUS_P5Q,
Guido Günther3e1647c52009-06-05 00:47:26 +0200256 ALC883_SONY_VAIO_TT,
Takashi Iwai4953550a2009-06-30 15:28:30 +0200257 ALC882_AUTO,
258 ALC882_MODEL_LAST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200259};
260
Takashi Iwaid4a86d82010-06-23 17:51:26 +0200261/* ALC680 models */
262enum {
263 ALC680_BASE,
264 ALC680_AUTO,
265 ALC680_MODEL_LAST,
266};
267
Kailang Yangdf694da2005-12-05 19:42:22 +0100268/* for GPIO Poll */
269#define GPIO_MASK 0x03
270
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200271/* extra amp-initialization sequence types */
272enum {
273 ALC_INIT_NONE,
274 ALC_INIT_DEFAULT,
275 ALC_INIT_GPIO1,
276 ALC_INIT_GPIO2,
277 ALC_INIT_GPIO3,
278};
279
Takashi Iwai6c819492009-08-10 18:47:44 +0200280struct alc_mic_route {
281 hda_nid_t pin;
282 unsigned char mux_idx;
283 unsigned char amix_idx;
284};
285
Kailang Yang9ad0e492010-09-14 23:22:00 +0200286struct alc_jack {
287 hda_nid_t nid;
288 int type;
289 struct snd_jack *jack;
290};
291
Takashi Iwai6c819492009-08-10 18:47:44 +0200292#define MUX_IDX_UNDEF ((unsigned char)-1)
293
Kailang Yangda00c242010-03-19 11:23:45 +0100294struct alc_customize_define {
295 unsigned int sku_cfg;
296 unsigned char port_connectivity;
297 unsigned char check_sum;
298 unsigned char customization;
299 unsigned char external_amp;
300 unsigned int enable_pcbeep:1;
301 unsigned int platform_type:1;
302 unsigned int swap:1;
303 unsigned int override:1;
304};
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 Iwai4953550a2009-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 Woithe7cf51e482006-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 Woithe7cf51e482006-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 Woithe7cf51e482006-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 Kluin4b35d2ca2009-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
Kailang Yangda00c242010-03-19 11:23:45 +01001467static int alc_auto_parse_customize_define(struct hda_codec *codec)
1468{
1469 unsigned int ass, tmp, i;
Takashi Iwai7fb56222010-03-22 17:09:47 +01001470 unsigned nid = 0;
Kailang Yangda00c242010-03-19 11:23:45 +01001471 struct alc_spec *spec = codec->spec;
1472
Takashi Iwaib6cbe512010-07-28 17:43:36 +02001473 spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
1474
Kailang Yangda00c242010-03-19 11:23:45 +01001475 ass = codec->subsystem_id & 0xffff;
Takashi Iwaib6cbe512010-07-28 17:43:36 +02001476 if (ass != codec->bus->pci->subsystem_device && (ass & 1))
Kailang Yangda00c242010-03-19 11:23:45 +01001477 goto do_sku;
1478
1479 nid = 0x1d;
1480 if (codec->vendor_id == 0x10ec0260)
1481 nid = 0x17;
1482 ass = snd_hda_codec_get_pincfg(codec, nid);
1483
1484 if (!(ass & 1)) {
1485 printk(KERN_INFO "hda_codec: %s: SKU not ready 0x%08x\n",
1486 codec->chip_name, ass);
1487 return -1;
1488 }
1489
1490 /* check sum */
1491 tmp = 0;
1492 for (i = 1; i < 16; i++) {
1493 if ((ass >> i) & 1)
1494 tmp++;
1495 }
1496 if (((ass >> 16) & 0xf) != tmp)
1497 return -1;
1498
1499 spec->cdefine.port_connectivity = ass >> 30;
1500 spec->cdefine.enable_pcbeep = (ass & 0x100000) >> 20;
1501 spec->cdefine.check_sum = (ass >> 16) & 0xf;
1502 spec->cdefine.customization = ass >> 8;
1503do_sku:
1504 spec->cdefine.sku_cfg = ass;
1505 spec->cdefine.external_amp = (ass & 0x38) >> 3;
1506 spec->cdefine.platform_type = (ass & 0x4) >> 2;
1507 spec->cdefine.swap = (ass & 0x2) >> 1;
1508 spec->cdefine.override = ass & 0x1;
1509
1510 snd_printd("SKU: Nid=0x%x sku_cfg=0x%08x\n",
1511 nid, spec->cdefine.sku_cfg);
1512 snd_printd("SKU: port_connectivity=0x%x\n",
1513 spec->cdefine.port_connectivity);
1514 snd_printd("SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep);
1515 snd_printd("SKU: check_sum=0x%08x\n", spec->cdefine.check_sum);
1516 snd_printd("SKU: customization=0x%08x\n", spec->cdefine.customization);
1517 snd_printd("SKU: external_amp=0x%x\n", spec->cdefine.external_amp);
1518 snd_printd("SKU: platform_type=0x%x\n", spec->cdefine.platform_type);
1519 snd_printd("SKU: swap=0x%x\n", spec->cdefine.swap);
1520 snd_printd("SKU: override=0x%x\n", spec->cdefine.override);
1521
1522 return 0;
1523}
1524
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001525/* check subsystem ID and set up device-specific initialization;
1526 * return 1 if initialized, 0 if invalid SSID
1527 */
1528/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
1529 * 31 ~ 16 : Manufacture ID
1530 * 15 ~ 8 : SKU ID
1531 * 7 ~ 0 : Assembly ID
1532 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
1533 */
1534static int alc_subsystem_id(struct hda_codec *codec,
1535 hda_nid_t porta, hda_nid_t porte,
Kailang Yang6227cdc2010-02-25 08:36:52 +01001536 hda_nid_t portd, hda_nid_t porti)
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001537{
1538 unsigned int ass, tmp, i;
1539 unsigned nid;
1540 struct alc_spec *spec = codec->spec;
1541
1542 ass = codec->subsystem_id & 0xffff;
1543 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
1544 goto do_sku;
1545
1546 /* invalid SSID, check the special NID pin defcfg instead */
1547 /*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04001548 * 31~30 : port connectivity
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001549 * 29~21 : reserve
1550 * 20 : PCBEEP input
1551 * 19~16 : Check sum (15:1)
1552 * 15~1 : Custom
1553 * 0 : override
1554 */
1555 nid = 0x1d;
1556 if (codec->vendor_id == 0x10ec0260)
1557 nid = 0x17;
1558 ass = snd_hda_codec_get_pincfg(codec, nid);
1559 snd_printd("realtek: No valid SSID, "
1560 "checking pincfg 0x%08x for NID 0x%x\n",
Takashi Iwaicb6605c2009-04-28 13:03:19 +02001561 ass, nid);
Kailang Yang6227cdc2010-02-25 08:36:52 +01001562 if (!(ass & 1))
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001563 return 0;
1564 if ((ass >> 30) != 1) /* no physical connection */
1565 return 0;
1566
1567 /* check sum */
1568 tmp = 0;
1569 for (i = 1; i < 16; i++) {
1570 if ((ass >> i) & 1)
1571 tmp++;
1572 }
1573 if (((ass >> 16) & 0xf) != tmp)
1574 return 0;
1575do_sku:
1576 snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
1577 ass & 0xffff, codec->vendor_id);
1578 /*
1579 * 0 : override
1580 * 1 : Swap Jack
1581 * 2 : 0 --> Desktop, 1 --> Laptop
1582 * 3~5 : External Amplifier control
1583 * 7~6 : Reserved
1584 */
1585 tmp = (ass & 0x38) >> 3; /* external Amp control */
1586 switch (tmp) {
1587 case 1:
1588 spec->init_amp = ALC_INIT_GPIO1;
1589 break;
1590 case 3:
1591 spec->init_amp = ALC_INIT_GPIO2;
1592 break;
1593 case 7:
1594 spec->init_amp = ALC_INIT_GPIO3;
1595 break;
1596 case 5:
1597 spec->init_amp = ALC_INIT_DEFAULT;
1598 break;
1599 }
1600
1601 /* is laptop or Desktop and enable the function "Mute internal speaker
1602 * when the external headphone out jack is plugged"
1603 */
1604 if (!(ass & 0x8000))
1605 return 1;
1606 /*
1607 * 10~8 : Jack location
1608 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
1609 * 14~13: Resvered
1610 * 15 : 1 --> enable the function "Mute internal speaker
1611 * when the external headphone out jack is plugged"
1612 */
Kailang Yangc9b58002007-10-16 14:30:01 +02001613 if (!spec->autocfg.hp_pins[0]) {
Takashi Iwai01d48252009-10-06 13:21:54 +02001614 hda_nid_t nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001615 tmp = (ass >> 11) & 0x3; /* HP to chassis */
1616 if (tmp == 0)
Takashi Iwai01d48252009-10-06 13:21:54 +02001617 nid = porta;
Kailang Yangc9b58002007-10-16 14:30:01 +02001618 else if (tmp == 1)
Takashi Iwai01d48252009-10-06 13:21:54 +02001619 nid = porte;
Kailang Yangc9b58002007-10-16 14:30:01 +02001620 else if (tmp == 2)
Takashi Iwai01d48252009-10-06 13:21:54 +02001621 nid = portd;
Kailang Yang6227cdc2010-02-25 08:36:52 +01001622 else if (tmp == 3)
1623 nid = porti;
Kailang Yangc9b58002007-10-16 14:30:01 +02001624 else
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001625 return 1;
Takashi Iwai01d48252009-10-06 13:21:54 +02001626 for (i = 0; i < spec->autocfg.line_outs; i++)
1627 if (spec->autocfg.line_out_pins[i] == nid)
1628 return 1;
1629 spec->autocfg.hp_pins[0] = nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001630 }
1631
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001632 alc_init_auto_hp(codec);
Takashi Iwai6c819492009-08-10 18:47:44 +02001633 alc_init_auto_mic(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001634 return 1;
1635}
Kailang Yangea1fb292008-08-26 12:58:38 +02001636
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001637static void alc_ssid_check(struct hda_codec *codec,
Kailang Yang6227cdc2010-02-25 08:36:52 +01001638 hda_nid_t porta, hda_nid_t porte,
1639 hda_nid_t portd, hda_nid_t porti)
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001640{
Kailang Yang6227cdc2010-02-25 08:36:52 +01001641 if (!alc_subsystem_id(codec, porta, porte, portd, porti)) {
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001642 struct alc_spec *spec = codec->spec;
1643 snd_printd("realtek: "
1644 "Enable default setup for auto mode as fallback\n");
1645 spec->init_amp = ALC_INIT_DEFAULT;
1646 alc_init_auto_hp(codec);
Takashi Iwai6c819492009-08-10 18:47:44 +02001647 alc_init_auto_mic(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001648 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001649}
1650
Takashi Iwai41e41f12005-06-08 14:48:49 +02001651/*
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001652 * Fix-up pin default configurations and add default verbs
Takashi Iwaif95474e2007-07-10 00:47:43 +02001653 */
1654
1655struct alc_pincfg {
1656 hda_nid_t nid;
1657 u32 val;
1658};
1659
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001660struct alc_fixup {
1661 const struct alc_pincfg *pins;
1662 const struct hda_verb *verbs;
1663};
1664
1665static void alc_pick_fixup(struct hda_codec *codec,
Takashi Iwaif95474e2007-07-10 00:47:43 +02001666 const struct snd_pci_quirk *quirk,
Takashi Iwai7fa90e82010-04-12 08:49:00 +02001667 const struct alc_fixup *fix,
1668 int pre_init)
Takashi Iwaif95474e2007-07-10 00:47:43 +02001669{
1670 const struct alc_pincfg *cfg;
1671
1672 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
1673 if (!quirk)
1674 return;
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001675 fix += quirk->value;
1676 cfg = fix->pins;
Takashi Iwai7fa90e82010-04-12 08:49:00 +02001677 if (pre_init && cfg) {
1678#ifdef CONFIG_SND_DEBUG_VERBOSE
1679 snd_printdd(KERN_INFO "hda_codec: %s: Apply pincfg for %s\n",
1680 codec->chip_name, quirk->name);
1681#endif
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001682 for (; cfg->nid; cfg++)
1683 snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
1684 }
Takashi Iwai7fa90e82010-04-12 08:49:00 +02001685 if (!pre_init && fix->verbs) {
1686#ifdef CONFIG_SND_DEBUG_VERBOSE
1687 snd_printdd(KERN_INFO "hda_codec: %s: Apply fix-verbs for %s\n",
1688 codec->chip_name, quirk->name);
1689#endif
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001690 add_verb(codec->spec, fix->verbs);
Takashi Iwai7fa90e82010-04-12 08:49:00 +02001691 }
Takashi Iwaif95474e2007-07-10 00:47:43 +02001692}
1693
Kailang Yang274693f2009-12-03 10:07:50 +01001694static int alc_read_coef_idx(struct hda_codec *codec,
1695 unsigned int coef_idx)
1696{
1697 unsigned int val;
1698 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
1699 coef_idx);
1700 val = snd_hda_codec_read(codec, 0x20, 0,
1701 AC_VERB_GET_PROC_COEF, 0);
1702 return val;
1703}
1704
Kailang Yang977ddd62010-09-15 10:02:29 +02001705static void alc_write_coef_idx(struct hda_codec *codec, unsigned int coef_idx,
1706 unsigned int coef_val)
1707{
1708 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
1709 coef_idx);
1710 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF,
1711 coef_val);
1712}
1713
Takashi Iwai757899a2010-07-30 10:48:14 +02001714/* set right pin controls for digital I/O */
1715static void alc_auto_init_digital(struct hda_codec *codec)
1716{
1717 struct alc_spec *spec = codec->spec;
1718 int i;
1719 hda_nid_t pin;
1720
1721 for (i = 0; i < spec->autocfg.dig_outs; i++) {
1722 pin = spec->autocfg.dig_out_pins[i];
1723 if (pin) {
1724 snd_hda_codec_write(codec, pin, 0,
1725 AC_VERB_SET_PIN_WIDGET_CONTROL,
1726 PIN_OUT);
1727 }
1728 }
1729 pin = spec->autocfg.dig_in_pin;
1730 if (pin)
1731 snd_hda_codec_write(codec, pin, 0,
1732 AC_VERB_SET_PIN_WIDGET_CONTROL,
1733 PIN_IN);
1734}
1735
1736/* parse digital I/Os and set up NIDs in BIOS auto-parse mode */
1737static void alc_auto_parse_digital(struct hda_codec *codec)
1738{
1739 struct alc_spec *spec = codec->spec;
1740 int i, err;
1741 hda_nid_t dig_nid;
1742
1743 /* support multiple SPDIFs; the secondary is set up as a slave */
1744 for (i = 0; i < spec->autocfg.dig_outs; i++) {
1745 err = snd_hda_get_connections(codec,
1746 spec->autocfg.dig_out_pins[i],
1747 &dig_nid, 1);
1748 if (err < 0)
1749 continue;
1750 if (!i) {
1751 spec->multiout.dig_out_nid = dig_nid;
1752 spec->dig_out_type = spec->autocfg.dig_out_type[0];
1753 } else {
1754 spec->multiout.slave_dig_outs = spec->slave_dig_outs;
1755 if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
1756 break;
1757 spec->slave_dig_outs[i - 1] = dig_nid;
1758 }
1759 }
1760
1761 if (spec->autocfg.dig_in_pin) {
1762 hda_nid_t dig_nid;
1763 err = snd_hda_get_connections(codec,
1764 spec->autocfg.dig_in_pin,
1765 &dig_nid, 1);
1766 if (err > 0)
1767 spec->dig_in_nid = dig_nid;
1768 }
1769}
1770
Takashi Iwaif95474e2007-07-10 00:47:43 +02001771/*
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001772 * ALC888
1773 */
1774
1775/*
1776 * 2ch mode
1777 */
1778static struct hda_verb alc888_4ST_ch2_intel_init[] = {
1779/* Mic-in jack as mic in */
1780 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1781 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1782/* Line-in jack as Line in */
1783 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1784 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1785/* Line-Out as Front */
1786 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
1787 { } /* end */
1788};
1789
1790/*
1791 * 4ch mode
1792 */
1793static struct hda_verb alc888_4ST_ch4_intel_init[] = {
1794/* Mic-in jack as mic in */
1795 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1796 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1797/* Line-in jack as Surround */
1798 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1799 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1800/* Line-Out as Front */
1801 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
1802 { } /* end */
1803};
1804
1805/*
1806 * 6ch mode
1807 */
1808static struct hda_verb alc888_4ST_ch6_intel_init[] = {
1809/* Mic-in jack as CLFE */
1810 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1811 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1812/* Line-in jack as Surround */
1813 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1814 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1815/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */
1816 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1817 { } /* end */
1818};
1819
1820/*
1821 * 8ch mode
1822 */
1823static struct hda_verb alc888_4ST_ch8_intel_init[] = {
1824/* Mic-in jack as CLFE */
1825 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1826 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1827/* Line-in jack as Surround */
1828 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1829 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1830/* Line-Out as Side */
1831 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1832 { } /* end */
1833};
1834
1835static struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
1836 { 2, alc888_4ST_ch2_intel_init },
1837 { 4, alc888_4ST_ch4_intel_init },
1838 { 6, alc888_4ST_ch6_intel_init },
1839 { 8, alc888_4ST_ch8_intel_init },
1840};
1841
1842/*
1843 * ALC888 Fujitsu Siemens Amillo xa3530
1844 */
1845
1846static struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
1847/* Front Mic: set to PIN_IN (empty by default) */
1848 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1849/* Connect Internal HP to Front */
1850 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1851 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1852 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1853/* Connect Bass HP to Front */
1854 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1855 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1856 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1857/* Connect Line-Out side jack (SPDIF) to Side */
1858 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1859 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1860 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1861/* Connect Mic jack to CLFE */
1862 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1863 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1864 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
1865/* Connect Line-in jack to Surround */
1866 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1867 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1868 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
1869/* Connect HP out jack to Front */
1870 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1871 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1872 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
1873/* Enable unsolicited event for HP jack and Line-out jack */
1874 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1875 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1876 {}
1877};
1878
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001879static void alc_automute_amp(struct hda_codec *codec)
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001880{
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001881 alc_automute_speaker(codec, 0);
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001882}
1883
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001884static void alc_automute_amp_unsol_event(struct hda_codec *codec,
1885 unsigned int res)
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001886{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001887 if (codec->vendor_id == 0x10ec0880)
1888 res >>= 28;
1889 else
1890 res >>= 26;
1891 if (res == ALC880_HP_EVENT)
1892 alc_automute_amp(codec);
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001893}
1894
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001895static void alc889_automute_setup(struct hda_codec *codec)
Wu Fengguang6732bd02009-07-30 09:19:14 +02001896{
1897 struct alc_spec *spec = codec->spec;
1898
1899 spec->autocfg.hp_pins[0] = 0x15;
1900 spec->autocfg.speaker_pins[0] = 0x14;
1901 spec->autocfg.speaker_pins[1] = 0x16;
1902 spec->autocfg.speaker_pins[2] = 0x17;
1903 spec->autocfg.speaker_pins[3] = 0x19;
1904 spec->autocfg.speaker_pins[4] = 0x1a;
Wu Fengguang6732bd02009-07-30 09:19:14 +02001905}
1906
1907static void alc889_intel_init_hook(struct hda_codec *codec)
1908{
1909 alc889_coef_init(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001910 alc_automute_amp(codec);
Wu Fengguang6732bd02009-07-30 09:19:14 +02001911}
1912
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001913static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001914{
1915 struct alc_spec *spec = codec->spec;
1916
1917 spec->autocfg.hp_pins[0] = 0x17; /* line-out */
1918 spec->autocfg.hp_pins[1] = 0x1b; /* hp */
1919 spec->autocfg.speaker_pins[0] = 0x14; /* speaker */
1920 spec->autocfg.speaker_pins[1] = 0x15; /* bass */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001921}
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001922
1923/*
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001924 * ALC888 Acer Aspire 4930G model
1925 */
1926
1927static struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
1928/* Front Mic: set to PIN_IN (empty by default) */
1929 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1930/* Unselect Front Mic by default in input mixer 3 */
1931 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001932/* Enable unsolicited event for HP jack */
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001933 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1934/* Connect Internal HP to front */
1935 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1936 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1937 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1938/* Connect HP out to front */
1939 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1940 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1941 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1942 { }
1943};
1944
Hector Martin3b315d72009-06-02 10:54:19 +02001945/*
Tony Vroond2fd4b02009-06-21 00:40:10 +01001946 * ALC888 Acer Aspire 6530G model
1947 */
1948
1949static struct hda_verb alc888_acer_aspire_6530g_verbs[] = {
Tony Vroond1284182010-04-05 16:30:43 +01001950/* Route to built-in subwoofer as well as speakers */
1951 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1952 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1953 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1954 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Tony Vroond2fd4b02009-06-21 00:40:10 +01001955/* Bias voltage on for external mic port */
1956 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
Emilio López320d5922009-06-25 08:18:44 +02001957/* Front Mic: set to PIN_IN (empty by default) */
1958 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1959/* Unselect Front Mic by default in input mixer 3 */
1960 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Tony Vroond2fd4b02009-06-21 00:40:10 +01001961/* Enable unsolicited event for HP jack */
1962 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1963/* Enable speaker output */
1964 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1965 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Tony Vroond1284182010-04-05 16:30:43 +01001966 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Tony Vroond2fd4b02009-06-21 00:40:10 +01001967/* Enable headphone output */
1968 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
1969 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1970 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Tony Vroond1284182010-04-05 16:30:43 +01001971 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
Tony Vroond2fd4b02009-06-21 00:40:10 +01001972 { }
1973};
1974
1975/*
Hector Martin018df412009-06-04 00:13:40 +02001976 * ALC889 Acer Aspire 8930G model
Hector Martin3b315d72009-06-02 10:54:19 +02001977 */
1978
Hector Martin018df412009-06-04 00:13:40 +02001979static struct hda_verb alc889_acer_aspire_8930g_verbs[] = {
Hector Martin3b315d72009-06-02 10:54:19 +02001980/* Front Mic: set to PIN_IN (empty by default) */
1981 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1982/* Unselect Front Mic by default in input mixer 3 */
1983 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
1984/* Enable unsolicited event for HP jack */
1985 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1986/* Connect Internal Front to Front */
1987 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1988 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1989 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1990/* Connect Internal Rear to Rear */
1991 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1992 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1993 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
1994/* Connect Internal CLFE to CLFE */
1995 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1996 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1997 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
1998/* Connect HP out to Front */
Hector Martin018df412009-06-04 00:13:40 +02001999 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
Hector Martin3b315d72009-06-02 10:54:19 +02002000 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2001 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
2002/* Enable all DACs */
2003/* DAC DISABLE/MUTE 1? */
2004/* setting bits 1-5 disables DAC nids 0x02-0x06 apparently. Init=0x38 */
2005 {0x20, AC_VERB_SET_COEF_INDEX, 0x03},
2006 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
2007/* DAC DISABLE/MUTE 2? */
2008/* some bit here disables the other DACs. Init=0x4900 */
2009 {0x20, AC_VERB_SET_COEF_INDEX, 0x08},
2010 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
Hector Martin018df412009-06-04 00:13:40 +02002011/* DMIC fix
2012 * This laptop has a stereo digital microphone. The mics are only 1cm apart
2013 * which makes the stereo useless. However, either the mic or the ALC889
2014 * makes the signal become a difference/sum signal instead of standard
2015 * stereo, which is annoying. So instead we flip this bit which makes the
2016 * codec replicate the sum signal to both channels, turning it into a
2017 * normal mono mic.
2018 */
2019/* DMIC_CONTROL? Init value = 0x0001 */
2020 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
2021 {0x20, AC_VERB_SET_PROC_COEF, 0x0003},
Hector Martin3b315d72009-06-02 10:54:19 +02002022 { }
2023};
2024
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002025static struct hda_input_mux alc888_2_capture_sources[2] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002026 /* Front mic only available on one ADC */
2027 {
2028 .num_items = 4,
2029 .items = {
2030 { "Mic", 0x0 },
2031 { "Line", 0x2 },
2032 { "CD", 0x4 },
2033 { "Front Mic", 0xb },
2034 },
2035 },
2036 {
2037 .num_items = 3,
2038 .items = {
2039 { "Mic", 0x0 },
2040 { "Line", 0x2 },
2041 { "CD", 0x4 },
2042 },
2043 }
2044};
2045
Tony Vroond2fd4b02009-06-21 00:40:10 +01002046static struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
2047 /* Interal mic only available on one ADC */
2048 {
Tony Vroon684a8842009-06-26 09:27:50 +01002049 .num_items = 5,
Tony Vroond2fd4b02009-06-21 00:40:10 +01002050 .items = {
2051 { "Ext Mic", 0x0 },
Tony Vroon684a8842009-06-26 09:27:50 +01002052 { "Line In", 0x2 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002053 { "CD", 0x4 },
Tony Vroon684a8842009-06-26 09:27:50 +01002054 { "Input Mix", 0xa },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002055 { "Int Mic", 0xb },
2056 },
2057 },
2058 {
Tony Vroon684a8842009-06-26 09:27:50 +01002059 .num_items = 4,
Tony Vroond2fd4b02009-06-21 00:40:10 +01002060 .items = {
2061 { "Ext Mic", 0x0 },
Tony Vroon684a8842009-06-26 09:27:50 +01002062 { "Line In", 0x2 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002063 { "CD", 0x4 },
Tony Vroon684a8842009-06-26 09:27:50 +01002064 { "Input Mix", 0xa },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002065 },
2066 }
2067};
2068
Hector Martin018df412009-06-04 00:13:40 +02002069static struct hda_input_mux alc889_capture_sources[3] = {
2070 /* Digital mic only available on first "ADC" */
2071 {
2072 .num_items = 5,
2073 .items = {
2074 { "Mic", 0x0 },
2075 { "Line", 0x2 },
2076 { "CD", 0x4 },
2077 { "Front Mic", 0xb },
2078 { "Input Mix", 0xa },
2079 },
2080 },
2081 {
2082 .num_items = 4,
2083 .items = {
2084 { "Mic", 0x0 },
2085 { "Line", 0x2 },
2086 { "CD", 0x4 },
2087 { "Input Mix", 0xa },
2088 },
2089 },
2090 {
2091 .num_items = 4,
2092 .items = {
2093 { "Mic", 0x0 },
2094 { "Line", 0x2 },
2095 { "CD", 0x4 },
2096 { "Input Mix", 0xa },
2097 },
2098 }
2099};
2100
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002101static struct snd_kcontrol_new alc888_base_mixer[] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002102 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2103 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2104 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2105 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2106 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
2107 HDA_OUTPUT),
2108 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2109 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2110 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2111 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2112 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
2113 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2114 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2115 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2116 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2117 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2118 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
2119 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002120 { } /* end */
2121};
2122
Hector Martin556eea92009-12-20 22:51:23 +01002123static struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = {
2124 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2125 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2126 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2127 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2128 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
2129 HDA_OUTPUT),
2130 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2131 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2132 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2133 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2134 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2135 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2136 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
2137 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2138 { } /* end */
2139};
2140
2141
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002142static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec)
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002143{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002144 struct alc_spec *spec = codec->spec;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002145
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002146 spec->autocfg.hp_pins[0] = 0x15;
2147 spec->autocfg.speaker_pins[0] = 0x14;
Łukasz Wojniłowicz7cef4cf2009-11-20 12:14:35 +01002148 spec->autocfg.speaker_pins[1] = 0x16;
2149 spec->autocfg.speaker_pins[2] = 0x17;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002150}
2151
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002152static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec)
Emilio López320d5922009-06-25 08:18:44 +02002153{
2154 struct alc_spec *spec = codec->spec;
2155
2156 spec->autocfg.hp_pins[0] = 0x15;
2157 spec->autocfg.speaker_pins[0] = 0x14;
2158 spec->autocfg.speaker_pins[1] = 0x16;
2159 spec->autocfg.speaker_pins[2] = 0x17;
Emilio López320d5922009-06-25 08:18:44 +02002160}
2161
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002162static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
Hector Martin3b315d72009-06-02 10:54:19 +02002163{
2164 struct alc_spec *spec = codec->spec;
2165
2166 spec->autocfg.hp_pins[0] = 0x15;
2167 spec->autocfg.speaker_pins[0] = 0x14;
2168 spec->autocfg.speaker_pins[1] = 0x16;
2169 spec->autocfg.speaker_pins[2] = 0x1b;
Hector Martin3b315d72009-06-02 10:54:19 +02002170}
2171
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002172/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002173 * ALC880 3-stack model
2174 *
2175 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002176 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
2177 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 */
2179
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002180static hda_nid_t alc880_dac_nids[4] = {
2181 /* front, rear, clfe, rear_surr */
2182 0x02, 0x05, 0x04, 0x03
2183};
2184
2185static hda_nid_t alc880_adc_nids[3] = {
2186 /* ADC0-2 */
2187 0x07, 0x08, 0x09,
2188};
2189
2190/* The datasheet says the node 0x07 is connected from inputs,
2191 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +01002192 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002194static hda_nid_t alc880_adc_nids_alt[2] = {
2195 /* ADC1-2 */
2196 0x08, 0x09,
2197};
2198
2199#define ALC880_DIGOUT_NID 0x06
2200#define ALC880_DIGIN_NID 0x0a
2201
2202static struct hda_input_mux alc880_capture_source = {
2203 .num_items = 4,
2204 .items = {
2205 { "Mic", 0x0 },
2206 { "Front Mic", 0x3 },
2207 { "Line", 0x2 },
2208 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002210};
2211
2212/* channel source setting (2/6 channel selection for 3-stack) */
2213/* 2ch mode */
2214static struct hda_verb alc880_threestack_ch2_init[] = {
2215 /* set line-in to input, mute it */
2216 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2217 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2218 /* set mic-in to input vref 80%, mute it */
2219 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2220 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 { } /* end */
2222};
2223
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002224/* 6ch mode */
2225static struct hda_verb alc880_threestack_ch6_init[] = {
2226 /* set line-in to output, unmute it */
2227 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2228 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2229 /* set mic-in to output, unmute it */
2230 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2231 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2232 { } /* end */
2233};
2234
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002235static struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002236 { 2, alc880_threestack_ch2_init },
2237 { 6, alc880_threestack_ch6_init },
2238};
2239
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002240static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002241 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002242 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02002243 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002244 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02002245 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2246 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002247 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2248 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2250 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2251 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2252 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2253 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2254 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2255 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
2256 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002258 {
2259 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2260 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002261 .info = alc_ch_mode_info,
2262 .get = alc_ch_mode_get,
2263 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002264 },
2265 { } /* end */
2266};
2267
2268/* capture mixer elements */
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002269static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
2270 struct snd_ctl_elem_info *uinfo)
2271{
2272 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2273 struct alc_spec *spec = codec->spec;
2274 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002275
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002276 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002277 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
2278 HDA_INPUT);
2279 err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002280 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002281 return err;
2282}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002284static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
2285 unsigned int size, unsigned int __user *tlv)
2286{
2287 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2288 struct alc_spec *spec = codec->spec;
2289 int err;
2290
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002291 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002292 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
2293 HDA_INPUT);
2294 err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002295 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002296 return err;
2297}
2298
2299typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
2300 struct snd_ctl_elem_value *ucontrol);
2301
2302static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
2303 struct snd_ctl_elem_value *ucontrol,
2304 getput_call_t func)
2305{
2306 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2307 struct alc_spec *spec = codec->spec;
2308 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
2309 int err;
2310
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002311 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002312 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[adc_idx],
2313 3, 0, HDA_INPUT);
2314 err = func(kcontrol, ucontrol);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002315 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002316 return err;
2317}
2318
2319static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
2320 struct snd_ctl_elem_value *ucontrol)
2321{
2322 return alc_cap_getput_caller(kcontrol, ucontrol,
2323 snd_hda_mixer_amp_volume_get);
2324}
2325
2326static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
2327 struct snd_ctl_elem_value *ucontrol)
2328{
2329 return alc_cap_getput_caller(kcontrol, ucontrol,
2330 snd_hda_mixer_amp_volume_put);
2331}
2332
2333/* capture mixer elements */
2334#define alc_cap_sw_info snd_ctl_boolean_stereo_info
2335
2336static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
2337 struct snd_ctl_elem_value *ucontrol)
2338{
2339 return alc_cap_getput_caller(kcontrol, ucontrol,
2340 snd_hda_mixer_amp_switch_get);
2341}
2342
2343static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
2344 struct snd_ctl_elem_value *ucontrol)
2345{
2346 return alc_cap_getput_caller(kcontrol, ucontrol,
2347 snd_hda_mixer_amp_switch_put);
2348}
2349
Takashi Iwaia23b6882009-03-23 15:21:36 +01002350#define _DEFINE_CAPMIX(num) \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002351 { \
2352 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2353 .name = "Capture Switch", \
2354 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
2355 .count = num, \
2356 .info = alc_cap_sw_info, \
2357 .get = alc_cap_sw_get, \
2358 .put = alc_cap_sw_put, \
2359 }, \
2360 { \
2361 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2362 .name = "Capture Volume", \
2363 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
2364 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
2365 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
2366 .count = num, \
2367 .info = alc_cap_vol_info, \
2368 .get = alc_cap_vol_get, \
2369 .put = alc_cap_vol_put, \
2370 .tlv = { .c = alc_cap_vol_tlv }, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002371 }
2372
2373#define _DEFINE_CAPSRC(num) \
Takashi Iwai3c3e9892008-10-31 17:48:56 +01002374 { \
2375 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2376 /* .name = "Capture Source", */ \
2377 .name = "Input Source", \
2378 .count = num, \
2379 .info = alc_mux_enum_info, \
2380 .get = alc_mux_enum_get, \
2381 .put = alc_mux_enum_put, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002382 }
2383
2384#define DEFINE_CAPMIX(num) \
2385static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
2386 _DEFINE_CAPMIX(num), \
2387 _DEFINE_CAPSRC(num), \
2388 { } /* end */ \
2389}
2390
2391#define DEFINE_CAPMIX_NOSRC(num) \
2392static struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
2393 _DEFINE_CAPMIX(num), \
2394 { } /* end */ \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002395}
2396
2397/* up to three ADCs */
2398DEFINE_CAPMIX(1);
2399DEFINE_CAPMIX(2);
2400DEFINE_CAPMIX(3);
Takashi Iwaia23b6882009-03-23 15:21:36 +01002401DEFINE_CAPMIX_NOSRC(1);
2402DEFINE_CAPMIX_NOSRC(2);
2403DEFINE_CAPMIX_NOSRC(3);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002404
2405/*
2406 * ALC880 5-stack model
2407 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002408 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
2409 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002410 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
2411 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
2412 */
2413
2414/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002415static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002416 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002417 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 { } /* end */
2419};
2420
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002421/* channel source setting (6/8 channel selection for 5-stack) */
2422/* 6ch mode */
2423static struct hda_verb alc880_fivestack_ch6_init[] = {
2424 /* set line-in to input, mute it */
2425 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2426 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002427 { } /* end */
2428};
2429
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002430/* 8ch mode */
2431static struct hda_verb alc880_fivestack_ch8_init[] = {
2432 /* set line-in to output, unmute it */
2433 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2434 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2435 { } /* end */
2436};
2437
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002438static struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002439 { 6, alc880_fivestack_ch6_init },
2440 { 8, alc880_fivestack_ch8_init },
2441};
2442
2443
2444/*
2445 * ALC880 6-stack model
2446 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002447 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
2448 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002449 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
2450 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
2451 */
2452
2453static hda_nid_t alc880_6st_dac_nids[4] = {
2454 /* front, rear, clfe, rear_surr */
2455 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002456};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002457
2458static struct hda_input_mux alc880_6stack_capture_source = {
2459 .num_items = 4,
2460 .items = {
2461 { "Mic", 0x0 },
2462 { "Front Mic", 0x1 },
2463 { "Line", 0x2 },
2464 { "CD", 0x4 },
2465 },
2466};
2467
2468/* fixed 8-channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002469static struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002470 { 8, NULL },
2471};
2472
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002473static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002474 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002475 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002476 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002477 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002478 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2479 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002480 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2481 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002482 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002483 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002484 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2485 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2486 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2487 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2488 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2489 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2490 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2491 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002492 {
2493 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2494 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002495 .info = alc_ch_mode_info,
2496 .get = alc_ch_mode_get,
2497 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02002498 },
2499 { } /* end */
2500};
2501
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002502
2503/*
2504 * ALC880 W810 model
2505 *
2506 * W810 has rear IO for:
2507 * Front (DAC 02)
2508 * Surround (DAC 03)
2509 * Center/LFE (DAC 04)
2510 * Digital out (06)
2511 *
2512 * The system also has a pair of internal speakers, and a headphone jack.
2513 * These are both connected to Line2 on the codec, hence to DAC 02.
Kailang Yangea1fb292008-08-26 12:58:38 +02002514 *
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002515 * There is a variable resistor to control the speaker or headphone
2516 * volume. This is a hardware-only device without a software API.
2517 *
2518 * Plugging headphones in will disable the internal speakers. This is
2519 * implemented in hardware, not via the driver using jack sense. In
2520 * a similar fashion, plugging into the rear socket marked "front" will
2521 * disable both the speakers and headphones.
2522 *
2523 * For input, there's a microphone jack, and an "audio in" jack.
2524 * These may not do anything useful with this driver yet, because I
2525 * haven't setup any initialization verbs for these yet...
2526 */
2527
2528static hda_nid_t alc880_w810_dac_nids[3] = {
2529 /* front, rear/surround, clfe */
2530 0x02, 0x03, 0x04
2531};
2532
2533/* fixed 6 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002534static struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002535 { 6, NULL }
2536};
2537
2538/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002539static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002540 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002541 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002542 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002543 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002544 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2545 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002546 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2547 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002548 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
2549 { } /* end */
2550};
2551
2552
2553/*
2554 * Z710V model
2555 *
2556 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002557 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
2558 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002559 */
2560
2561static hda_nid_t alc880_z71v_dac_nids[1] = {
2562 0x02
2563};
2564#define ALC880_Z71V_HP_DAC 0x03
2565
2566/* fixed 2 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002567static struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002568 { 2, NULL }
2569};
2570
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002571static struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002572 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002573 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002574 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002575 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002576 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2577 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2578 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2579 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2580 { } /* end */
2581};
2582
2583
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002584/*
2585 * ALC880 F1734 model
2586 *
2587 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
2588 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
2589 */
2590
2591static hda_nid_t alc880_f1734_dac_nids[1] = {
2592 0x03
2593};
2594#define ALC880_F1734_HP_DAC 0x02
2595
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002596static struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002597 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002598 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01002599 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2600 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002601 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2602 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01002603 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2604 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002605 { } /* end */
2606};
2607
Takashi Iwai937b4162008-02-11 14:52:36 +01002608static struct hda_input_mux alc880_f1734_capture_source = {
2609 .num_items = 2,
2610 .items = {
2611 { "Mic", 0x1 },
2612 { "CD", 0x4 },
2613 },
2614};
2615
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002616
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002617/*
2618 * ALC880 ASUS model
2619 *
2620 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
2621 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
2622 * Mic = 0x18, Line = 0x1a
2623 */
2624
2625#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
2626#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
2627
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002628static struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002629 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002630 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002631 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002632 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002633 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2634 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002635 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2636 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002637 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2638 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2639 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2640 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2641 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2642 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002643 {
2644 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2645 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002646 .info = alc_ch_mode_info,
2647 .get = alc_ch_mode_get,
2648 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02002649 },
2650 { } /* end */
2651};
2652
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002653/*
2654 * ALC880 ASUS W1V model
2655 *
2656 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
2657 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
2658 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
2659 */
2660
2661/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002662static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002663 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
2664 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002665 { } /* end */
2666};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002667
Kailang Yangdf694da2005-12-05 19:42:22 +01002668/* TCL S700 */
2669static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
2670 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2671 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
2672 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
2673 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
2674 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
2675 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
2676 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
2677 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
2678 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01002679 { } /* end */
2680};
2681
Kailang Yangccc656c2006-10-17 12:32:26 +02002682/* Uniwill */
2683static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002684 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2685 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2686 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2687 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002688 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2689 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2690 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2691 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2692 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2693 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2694 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2695 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2696 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2697 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2698 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2699 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002700 {
2701 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2702 .name = "Channel Mode",
2703 .info = alc_ch_mode_info,
2704 .get = alc_ch_mode_get,
2705 .put = alc_ch_mode_put,
2706 },
2707 { } /* end */
2708};
2709
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002710static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
2711 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2712 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2713 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2714 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
2715 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2716 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2717 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2718 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2719 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2720 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
2721 { } /* end */
2722};
2723
Kailang Yangccc656c2006-10-17 12:32:26 +02002724static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002725 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2726 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2727 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2728 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002729 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2730 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2731 { } /* end */
2732};
2733
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01002735 * virtual master controls
2736 */
2737
2738/*
2739 * slave controls for virtual master
2740 */
2741static const char *alc_slave_vols[] = {
2742 "Front Playback Volume",
2743 "Surround Playback Volume",
2744 "Center Playback Volume",
2745 "LFE Playback Volume",
2746 "Side Playback Volume",
2747 "Headphone Playback Volume",
2748 "Speaker Playback Volume",
2749 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002750 "Line-Out Playback Volume",
Takashi Iwai26f5df22008-11-03 17:39:46 +01002751 "PCM Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002752 NULL,
2753};
2754
2755static const char *alc_slave_sws[] = {
2756 "Front Playback Switch",
2757 "Surround Playback Switch",
2758 "Center Playback Switch",
2759 "LFE Playback Switch",
2760 "Side Playback Switch",
2761 "Headphone Playback Switch",
2762 "Speaker Playback Switch",
2763 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01002764 "IEC958 Playback Switch",
Takashi Iwai23033b22009-12-08 12:36:52 +01002765 "Line-Out Playback Switch",
2766 "PCM Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002767 NULL,
2768};
2769
2770/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002771 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 */
Takashi Iwai603c4012008-07-30 15:01:44 +02002773
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002774#define NID_MAPPING (-1)
2775
2776#define SUBDEV_SPEAKER_ (0 << 6)
2777#define SUBDEV_HP_ (1 << 6)
2778#define SUBDEV_LINE_ (2 << 6)
2779#define SUBDEV_SPEAKER(x) (SUBDEV_SPEAKER_ | ((x) & 0x3f))
2780#define SUBDEV_HP(x) (SUBDEV_HP_ | ((x) & 0x3f))
2781#define SUBDEV_LINE(x) (SUBDEV_LINE_ | ((x) & 0x3f))
2782
Takashi Iwai603c4012008-07-30 15:01:44 +02002783static void alc_free_kctls(struct hda_codec *codec);
2784
Takashi Iwai67d634c2009-11-16 15:35:59 +01002785#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002786/* additional beep mixers; the actual parameters are overwritten at build */
2787static struct snd_kcontrol_new alc_beep_mixer[] = {
2788 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
Jaroslav Kysela123c07a2009-10-21 14:48:23 +02002789 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002790 { } /* end */
2791};
Takashi Iwai67d634c2009-11-16 15:35:59 +01002792#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002793
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794static int alc_build_controls(struct hda_codec *codec)
2795{
2796 struct alc_spec *spec = codec->spec;
Takashi Iwai2f44f842010-06-22 11:12:32 +02002797 struct snd_kcontrol *kctl = NULL;
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002798 struct snd_kcontrol_new *knew;
2799 int i, j, err;
2800 unsigned int u;
2801 hda_nid_t nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802
2803 for (i = 0; i < spec->num_mixers; i++) {
2804 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
2805 if (err < 0)
2806 return err;
2807 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002808 if (spec->cap_mixer) {
2809 err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
2810 if (err < 0)
2811 return err;
2812 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002814 err = snd_hda_create_spdif_out_ctls(codec,
2815 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816 if (err < 0)
2817 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002818 if (!spec->no_analog) {
2819 err = snd_hda_create_spdif_share_sw(codec,
2820 &spec->multiout);
2821 if (err < 0)
2822 return err;
2823 spec->multiout.share_spdif = 1;
2824 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 }
2826 if (spec->dig_in_nid) {
2827 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
2828 if (err < 0)
2829 return err;
2830 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01002831
Takashi Iwai67d634c2009-11-16 15:35:59 +01002832#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002833 /* create beep controls if needed */
2834 if (spec->beep_amp) {
2835 struct snd_kcontrol_new *knew;
2836 for (knew = alc_beep_mixer; knew->name; knew++) {
2837 struct snd_kcontrol *kctl;
2838 kctl = snd_ctl_new1(knew, codec);
2839 if (!kctl)
2840 return -ENOMEM;
2841 kctl->private_value = spec->beep_amp;
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01002842 err = snd_hda_ctl_add(codec, 0, kctl);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002843 if (err < 0)
2844 return err;
2845 }
2846 }
Takashi Iwai67d634c2009-11-16 15:35:59 +01002847#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002848
Takashi Iwai2134ea42008-01-10 16:53:55 +01002849 /* if we have no master control, let's create it */
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002850 if (!spec->no_analog &&
2851 !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002852 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01002853 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002854 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01002855 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002856 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01002857 if (err < 0)
2858 return err;
2859 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002860 if (!spec->no_analog &&
2861 !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002862 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
2863 NULL, alc_slave_sws);
2864 if (err < 0)
2865 return err;
2866 }
2867
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002868 /* assign Capture Source enums to NID */
Takashi Iwaifbe618f2010-06-11 11:24:58 +02002869 if (spec->capsrc_nids || spec->adc_nids) {
2870 kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
2871 if (!kctl)
2872 kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
2873 for (i = 0; kctl && i < kctl->count; i++) {
2874 hda_nid_t *nids = spec->capsrc_nids;
2875 if (!nids)
2876 nids = spec->adc_nids;
2877 err = snd_hda_add_nid(codec, kctl, i, nids[i]);
2878 if (err < 0)
2879 return err;
2880 }
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002881 }
2882 if (spec->cap_mixer) {
2883 const char *kname = kctl ? kctl->id.name : NULL;
2884 for (knew = spec->cap_mixer; knew->name; knew++) {
2885 if (kname && strcmp(knew->name, kname) == 0)
2886 continue;
2887 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
2888 for (i = 0; kctl && i < kctl->count; i++) {
2889 err = snd_hda_add_nid(codec, kctl, i,
2890 spec->adc_nids[i]);
2891 if (err < 0)
2892 return err;
2893 }
2894 }
2895 }
2896
2897 /* other nid->control mapping */
2898 for (i = 0; i < spec->num_mixers; i++) {
2899 for (knew = spec->mixers[i]; knew->name; knew++) {
2900 if (knew->iface != NID_MAPPING)
2901 continue;
2902 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
2903 if (kctl == NULL)
2904 continue;
2905 u = knew->subdevice;
2906 for (j = 0; j < 4; j++, u >>= 8) {
2907 nid = u & 0x3f;
2908 if (nid == 0)
2909 continue;
2910 switch (u & 0xc0) {
2911 case SUBDEV_SPEAKER_:
2912 nid = spec->autocfg.speaker_pins[nid];
2913 break;
2914 case SUBDEV_LINE_:
2915 nid = spec->autocfg.line_out_pins[nid];
2916 break;
2917 case SUBDEV_HP_:
2918 nid = spec->autocfg.hp_pins[nid];
2919 break;
2920 default:
2921 continue;
2922 }
2923 err = snd_hda_add_nid(codec, kctl, 0, nid);
2924 if (err < 0)
2925 return err;
2926 }
2927 u = knew->private_value;
2928 for (j = 0; j < 4; j++, u >>= 8) {
2929 nid = u & 0xff;
2930 if (nid == 0)
2931 continue;
2932 err = snd_hda_add_nid(codec, kctl, 0, nid);
2933 if (err < 0)
2934 return err;
2935 }
2936 }
2937 }
Takashi Iwaibae84e72010-03-22 08:30:20 +01002938
2939 alc_free_kctls(codec); /* no longer needed */
2940
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941 return 0;
2942}
2943
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002944
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945/*
2946 * initialize the codec volumes, etc
2947 */
2948
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002949/*
2950 * generic initialization of ADC, input mixers and output mixers
2951 */
2952static struct hda_verb alc880_volume_init_verbs[] = {
2953 /*
2954 * Unmute ADC0-2 and set the default input to mic-in
2955 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002956 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002957 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002958 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002959 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002960 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002961 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002963 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2964 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002965 * Note: PASD motherboards uses the Line In 2 as the input for front
2966 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002968 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02002969 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2970 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2971 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2972 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2973 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2974 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2975 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002977 /*
2978 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002980 /* set vol=0 to output mixers */
2981 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2982 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2983 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2984 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2985 /* set up input amps for analog loopback */
2986 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002987 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2988 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002989 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2990 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002991 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2992 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002993 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2994 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995
2996 { }
2997};
2998
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002999/*
3000 * 3-stack pin configuration:
3001 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
3002 */
3003static struct hda_verb alc880_pin_3stack_init_verbs[] = {
3004 /*
3005 * preset connection lists of input pins
3006 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
3007 */
3008 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
3009 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3010 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
3011
3012 /*
3013 * Set pin mode and muting
3014 */
3015 /* set front pin widgets 0x14 for output */
3016 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3017 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3018 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3019 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3020 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3021 /* Mic2 (as headphone out) for HP output */
3022 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3023 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3024 /* Line In pin widget for input */
3025 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3026 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3027 /* Line2 (as front mic) pin widget for input and vref at 80% */
3028 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3029 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3030 /* CD pin widget for input */
3031 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3032
3033 { }
3034};
3035
3036/*
3037 * 5-stack pin configuration:
3038 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
3039 * line-in/side = 0x1a, f-mic = 0x1b
3040 */
3041static struct hda_verb alc880_pin_5stack_init_verbs[] = {
3042 /*
3043 * preset connection lists of input pins
3044 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
3045 */
3046 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3047 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
3048
3049 /*
3050 * Set pin mode and muting
3051 */
3052 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02003053 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3054 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3055 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3056 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003057 /* unmute pins for output (no gain on this amp) */
3058 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3059 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3060 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3061 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3062
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02003064 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003065 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3066 /* Mic2 (as headphone out) for HP output */
3067 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02003068 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003069 /* Line In pin widget for input */
3070 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3071 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3072 /* Line2 (as front mic) pin widget for input and vref at 80% */
3073 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3074 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3075 /* CD pin widget for input */
3076 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077
3078 { }
3079};
3080
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003081/*
3082 * W810 pin configuration:
3083 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
3084 */
3085static struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086 /* hphone/speaker input selector: front DAC */
3087 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
3088
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003089 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3090 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3091 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3092 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3093 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3094 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3095
3096 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02003097 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099 { }
3100};
3101
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003102/*
3103 * Z71V pin configuration:
3104 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
3105 */
3106static struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003107 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003108 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02003109 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003110 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02003111
Takashi Iwai16ded522005-06-10 19:58:24 +02003112 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003113 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02003114 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003115 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02003116
3117 { }
3118};
3119
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003120/*
3121 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003122 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
3123 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003124 */
3125static struct hda_verb alc880_pin_6stack_init_verbs[] = {
3126 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3127
Takashi Iwai16ded522005-06-10 19:58:24 +02003128 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003129 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003130 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003131 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003132 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003133 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003134 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003135 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3136
Takashi Iwai16ded522005-06-10 19:58:24 +02003137 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003138 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003139 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003140 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003141 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003142 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003143 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02003144 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003145 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02003146
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003147 { }
3148};
Takashi Iwai16ded522005-06-10 19:58:24 +02003149
Kailang Yangccc656c2006-10-17 12:32:26 +02003150/*
3151 * Uniwill pin configuration:
3152 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
3153 * line = 0x1a
3154 */
3155static struct hda_verb alc880_uniwill_init_verbs[] = {
3156 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3157
3158 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3159 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3160 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3161 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3162 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3163 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3164 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3165 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3166 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3167 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3168 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3169 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3170 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3171 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3172
3173 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3174 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3175 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3176 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3177 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3178 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3179 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
3180 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
3181 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3182
3183 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3184 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
3185
3186 { }
3187};
3188
3189/*
3190* Uniwill P53
Kailang Yangea1fb292008-08-26 12:58:38 +02003191* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
Kailang Yangccc656c2006-10-17 12:32:26 +02003192 */
3193static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
3194 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3195
3196 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3197 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3198 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3199 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3200 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3201 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3202 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3203 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3204 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3205 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3206 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3207 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3208
3209 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3210 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3211 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3212 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3213 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3214 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3215
3216 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3217 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
3218
3219 { }
3220};
3221
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003222static struct hda_verb alc880_beep_init_verbs[] = {
3223 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
3224 { }
3225};
3226
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003227/* auto-toggle front mic */
3228static void alc880_uniwill_mic_automute(struct hda_codec *codec)
3229{
3230 unsigned int present;
3231 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02003232
Wu Fengguang864f92b2009-11-18 12:38:02 +08003233 present = snd_hda_jack_detect(codec, 0x18);
Takashi Iwai47fd8302007-08-10 17:11:07 +02003234 bits = present ? HDA_AMP_MUTE : 0;
3235 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003236}
3237
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003238static void alc880_uniwill_setup(struct hda_codec *codec)
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003239{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003240 struct alc_spec *spec = codec->spec;
3241
3242 spec->autocfg.hp_pins[0] = 0x14;
3243 spec->autocfg.speaker_pins[0] = 0x15;
3244 spec->autocfg.speaker_pins[0] = 0x16;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003245}
3246
3247static void alc880_uniwill_init_hook(struct hda_codec *codec)
3248{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003249 alc_automute_amp(codec);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003250 alc880_uniwill_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02003251}
3252
3253static void alc880_uniwill_unsol_event(struct hda_codec *codec,
3254 unsigned int res)
3255{
3256 /* Looks like the unsol event is incompatible with the standard
3257 * definition. 4bit tag is placed at 28 bit!
3258 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003259 switch (res >> 28) {
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003260 case ALC880_MIC_EVENT:
3261 alc880_uniwill_mic_automute(codec);
3262 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003263 default:
3264 alc_automute_amp_unsol_event(codec, res);
3265 break;
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003266 }
Kailang Yangccc656c2006-10-17 12:32:26 +02003267}
3268
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003269static void alc880_uniwill_p53_setup(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02003270{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003271 struct alc_spec *spec = codec->spec;
Kailang Yangccc656c2006-10-17 12:32:26 +02003272
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003273 spec->autocfg.hp_pins[0] = 0x14;
3274 spec->autocfg.speaker_pins[0] = 0x15;
Kailang Yangccc656c2006-10-17 12:32:26 +02003275}
3276
3277static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
3278{
3279 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02003280
Kailang Yangccc656c2006-10-17 12:32:26 +02003281 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02003282 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
3283 present &= HDA_AMP_VOLMASK;
3284 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
3285 HDA_AMP_VOLMASK, present);
3286 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
3287 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02003288}
Takashi Iwai47fd8302007-08-10 17:11:07 +02003289
Kailang Yangccc656c2006-10-17 12:32:26 +02003290static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
3291 unsigned int res)
3292{
3293 /* Looks like the unsol event is incompatible with the standard
3294 * definition. 4bit tag is placed at 28 bit!
3295 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003296 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02003297 alc880_uniwill_p53_dcvol_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003298 else
3299 alc_automute_amp_unsol_event(codec, res);
Kailang Yangccc656c2006-10-17 12:32:26 +02003300}
3301
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003302/*
3303 * F1734 pin configuration:
3304 * HP = 0x14, speaker-out = 0x15, mic = 0x18
3305 */
3306static struct hda_verb alc880_pin_f1734_init_verbs[] = {
Michael Gruberee7a9c72008-03-10 11:30:59 +01003307 {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003308 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
3309 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
3310 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
3311 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
3312
3313 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3314 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3315 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3316 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3317
3318 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3319 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Michael Gruberee7a9c72008-03-10 11:30:59 +01003320 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003321 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3322 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3323 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3324 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3325 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3326 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02003327
Takashi Iwai937b4162008-02-11 14:52:36 +01003328 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
3329 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
3330
Takashi Iwai16ded522005-06-10 19:58:24 +02003331 { }
3332};
3333
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003334/*
3335 * ASUS pin configuration:
3336 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
3337 */
3338static struct hda_verb alc880_pin_asus_init_verbs[] = {
3339 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
3340 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
3341 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
3342 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
3343
3344 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3345 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3346 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3347 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3348 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3349 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3350 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3351 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3352
3353 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3354 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3355 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3356 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3357 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3358 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3359 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3360 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3361 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02003362
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003363 { }
3364};
3365
3366/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003367#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
3368#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
David Heidelberger64a8be72009-06-08 16:15:18 +02003369#define alc880_gpio3_init_verbs alc_gpio3_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003370
Kailang Yangdf694da2005-12-05 19:42:22 +01003371/* Clevo m520g init */
3372static struct hda_verb alc880_pin_clevo_init_verbs[] = {
3373 /* headphone output */
3374 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3375 /* line-out */
3376 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3377 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3378 /* Line-in */
3379 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3380 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3381 /* CD */
3382 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3383 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3384 /* Mic1 (rear panel) */
3385 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3386 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3387 /* Mic2 (front panel) */
3388 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3389 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3390 /* headphone */
3391 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3392 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3393 /* change to EAPD mode */
3394 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3395 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3396
3397 { }
3398};
3399
3400static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02003401 /* change to EAPD mode */
3402 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3403 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3404
Kailang Yangdf694da2005-12-05 19:42:22 +01003405 /* Headphone output */
3406 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3407 /* Front output*/
3408 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3409 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
3410
3411 /* Line In pin widget for input */
3412 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3413 /* CD pin widget for input */
3414 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3415 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3416 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3417
3418 /* change to EAPD mode */
3419 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3420 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
3421
3422 { }
3423};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003424
3425/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003426 * LG m1 express dual
3427 *
3428 * Pin assignment:
3429 * Rear Line-In/Out (blue): 0x14
3430 * Build-in Mic-In: 0x15
3431 * Speaker-out: 0x17
3432 * HP-Out (green): 0x1b
3433 * Mic-In/Out (red): 0x19
3434 * SPDIF-Out: 0x1e
3435 */
3436
3437/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
3438static hda_nid_t alc880_lg_dac_nids[3] = {
3439 0x05, 0x02, 0x03
3440};
3441
3442/* seems analog CD is not working */
3443static struct hda_input_mux alc880_lg_capture_source = {
3444 .num_items = 3,
3445 .items = {
3446 { "Mic", 0x1 },
3447 { "Line", 0x5 },
3448 { "Internal Mic", 0x6 },
3449 },
3450};
3451
3452/* 2,4,6 channel modes */
3453static struct hda_verb alc880_lg_ch2_init[] = {
3454 /* set line-in and mic-in to input */
3455 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
3456 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3457 { }
3458};
3459
3460static struct hda_verb alc880_lg_ch4_init[] = {
3461 /* set line-in to out and mic-in to input */
3462 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3463 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3464 { }
3465};
3466
3467static struct hda_verb alc880_lg_ch6_init[] = {
3468 /* set line-in and mic-in to output */
3469 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3470 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3471 { }
3472};
3473
3474static struct hda_channel_mode alc880_lg_ch_modes[3] = {
3475 { 2, alc880_lg_ch2_init },
3476 { 4, alc880_lg_ch4_init },
3477 { 6, alc880_lg_ch6_init },
3478};
3479
3480static struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003481 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
3482 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003483 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3484 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
3485 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
3486 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
3487 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
3488 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
3489 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3490 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
3491 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
3492 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
3493 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
3494 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
3495 {
3496 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3497 .name = "Channel Mode",
3498 .info = alc_ch_mode_info,
3499 .get = alc_ch_mode_get,
3500 .put = alc_ch_mode_put,
3501 },
3502 { } /* end */
3503};
3504
3505static struct hda_verb alc880_lg_init_verbs[] = {
3506 /* set capture source to mic-in */
3507 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3508 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3509 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3510 /* mute all amp mixer inputs */
3511 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02003512 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
3513 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003514 /* line-in to input */
3515 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3516 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3517 /* built-in mic */
3518 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3519 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3520 /* speaker-out */
3521 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3522 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3523 /* mic-in to input */
3524 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3525 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3526 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3527 /* HP-out */
3528 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
3529 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3530 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3531 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003532 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003533 { }
3534};
3535
3536/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003537static void alc880_lg_setup(struct hda_codec *codec)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003538{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003539 struct alc_spec *spec = codec->spec;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003540
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003541 spec->autocfg.hp_pins[0] = 0x1b;
3542 spec->autocfg.speaker_pins[0] = 0x17;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003543}
3544
3545/*
Takashi Iwaid6815182006-03-23 16:06:23 +01003546 * LG LW20
3547 *
3548 * Pin assignment:
3549 * Speaker-out: 0x14
3550 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003551 * Built-in Mic-In: 0x19
3552 * Line-In: 0x1b
3553 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01003554 * SPDIF-Out: 0x1e
3555 */
3556
Takashi Iwaid6815182006-03-23 16:06:23 +01003557static struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003558 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01003559 .items = {
3560 { "Mic", 0x0 },
3561 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003562 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003563 },
3564};
3565
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003566#define alc880_lg_lw_modes alc880_threestack_modes
3567
Takashi Iwaid6815182006-03-23 16:06:23 +01003568static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003569 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3570 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
3571 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
3572 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
3573 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
3574 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
3575 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
3576 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
3577 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
3578 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01003579 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3580 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3581 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
3582 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003583 {
3584 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3585 .name = "Channel Mode",
3586 .info = alc_ch_mode_info,
3587 .get = alc_ch_mode_get,
3588 .put = alc_ch_mode_put,
3589 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003590 { } /* end */
3591};
3592
3593static struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003594 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3595 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
3596 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
3597
Takashi Iwaid6815182006-03-23 16:06:23 +01003598 /* set capture source to mic-in */
3599 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3600 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3601 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02003602 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01003603 /* speaker-out */
3604 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3605 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3606 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01003607 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3608 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3609 /* mic-in to input */
3610 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3611 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3612 /* built-in mic */
3613 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3614 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3615 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003616 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaid6815182006-03-23 16:06:23 +01003617 { }
3618};
3619
3620/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003621static void alc880_lg_lw_setup(struct hda_codec *codec)
Takashi Iwaid6815182006-03-23 16:06:23 +01003622{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003623 struct alc_spec *spec = codec->spec;
Takashi Iwaid6815182006-03-23 16:06:23 +01003624
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003625 spec->autocfg.hp_pins[0] = 0x1b;
3626 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid6815182006-03-23 16:06:23 +01003627}
3628
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003629static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
3630 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3631 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
3632 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3633 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3634 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3635 HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
3636 { } /* end */
3637};
3638
3639static struct hda_input_mux alc880_medion_rim_capture_source = {
3640 .num_items = 2,
3641 .items = {
3642 { "Mic", 0x0 },
3643 { "Internal Mic", 0x1 },
3644 },
3645};
3646
3647static struct hda_verb alc880_medion_rim_init_verbs[] = {
3648 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3649
3650 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3651 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3652
3653 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3654 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3655 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3656 /* Mic2 (as headphone out) for HP output */
3657 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3658 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3659 /* Internal Speaker */
3660 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3661 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3662
3663 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3664 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3665
3666 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3667 { }
3668};
3669
3670/* toggle speaker-output according to the hp-jack state */
3671static void alc880_medion_rim_automute(struct hda_codec *codec)
3672{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003673 struct alc_spec *spec = codec->spec;
3674 alc_automute_amp(codec);
3675 /* toggle EAPD */
3676 if (spec->jack_present)
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003677 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
3678 else
3679 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
3680}
3681
3682static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
3683 unsigned int res)
3684{
3685 /* Looks like the unsol event is incompatible with the standard
3686 * definition. 4bit tag is placed at 28 bit!
3687 */
3688 if ((res >> 28) == ALC880_HP_EVENT)
3689 alc880_medion_rim_automute(codec);
3690}
3691
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003692static void alc880_medion_rim_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003693{
3694 struct alc_spec *spec = codec->spec;
3695
3696 spec->autocfg.hp_pins[0] = 0x14;
3697 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003698}
3699
Takashi Iwaicb53c622007-08-10 17:21:45 +02003700#ifdef CONFIG_SND_HDA_POWER_SAVE
3701static struct hda_amp_list alc880_loopbacks[] = {
3702 { 0x0b, HDA_INPUT, 0 },
3703 { 0x0b, HDA_INPUT, 1 },
3704 { 0x0b, HDA_INPUT, 2 },
3705 { 0x0b, HDA_INPUT, 3 },
3706 { 0x0b, HDA_INPUT, 4 },
3707 { } /* end */
3708};
3709
3710static struct hda_amp_list alc880_lg_loopbacks[] = {
3711 { 0x0b, HDA_INPUT, 1 },
3712 { 0x0b, HDA_INPUT, 6 },
3713 { 0x0b, HDA_INPUT, 7 },
3714 { } /* end */
3715};
3716#endif
3717
Takashi Iwaid6815182006-03-23 16:06:23 +01003718/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003719 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003720 */
Takashi Iwai16ded522005-06-10 19:58:24 +02003721
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722static int alc_init(struct hda_codec *codec)
3723{
3724 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003725 unsigned int i;
3726
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02003727 alc_fix_pll(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02003728 alc_auto_init_amp(codec, spec->init_amp);
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02003729
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003730 for (i = 0; i < spec->num_init_verbs; i++)
3731 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003732
3733 if (spec->init_hook)
3734 spec->init_hook(codec);
3735
Takashi Iwai9e5341b2010-09-21 09:57:06 +02003736 hda_call_check_power_status(codec, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003737 return 0;
3738}
3739
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003740static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
3741{
3742 struct alc_spec *spec = codec->spec;
3743
3744 if (spec->unsol_event)
3745 spec->unsol_event(codec, res);
3746}
3747
Takashi Iwaicb53c622007-08-10 17:21:45 +02003748#ifdef CONFIG_SND_HDA_POWER_SAVE
3749static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
3750{
3751 struct alc_spec *spec = codec->spec;
3752 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
3753}
3754#endif
3755
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756/*
3757 * Analog playback callbacks
3758 */
3759static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
3760 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003761 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003762{
3763 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01003764 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
3765 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766}
3767
3768static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
3769 struct hda_codec *codec,
3770 unsigned int stream_tag,
3771 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003772 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773{
3774 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003775 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
3776 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777}
3778
3779static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3780 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003781 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782{
3783 struct alc_spec *spec = codec->spec;
3784 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
3785}
3786
3787/*
3788 * Digital out
3789 */
3790static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
3791 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003792 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793{
3794 struct alc_spec *spec = codec->spec;
3795 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
3796}
3797
Takashi Iwai6b97eb42007-04-05 14:51:48 +02003798static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
3799 struct hda_codec *codec,
3800 unsigned int stream_tag,
3801 unsigned int format,
3802 struct snd_pcm_substream *substream)
3803{
3804 struct alc_spec *spec = codec->spec;
3805 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
3806 stream_tag, format, substream);
3807}
3808
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01003809static int alc880_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3810 struct hda_codec *codec,
3811 struct snd_pcm_substream *substream)
3812{
3813 struct alc_spec *spec = codec->spec;
3814 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
3815}
3816
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
3818 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003819 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003820{
3821 struct alc_spec *spec = codec->spec;
3822 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
3823}
3824
3825/*
3826 * Analog capture
3827 */
Takashi Iwai63300792008-01-24 15:31:36 +01003828static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829 struct hda_codec *codec,
3830 unsigned int stream_tag,
3831 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003832 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833{
3834 struct alc_spec *spec = codec->spec;
3835
Takashi Iwai63300792008-01-24 15:31:36 +01003836 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837 stream_tag, 0, format);
3838 return 0;
3839}
3840
Takashi Iwai63300792008-01-24 15:31:36 +01003841static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003842 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003843 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844{
3845 struct alc_spec *spec = codec->spec;
3846
Takashi Iwai888afa12008-03-18 09:57:50 +01003847 snd_hda_codec_cleanup_stream(codec,
3848 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849 return 0;
3850}
3851
Takashi Iwai840b64c2010-07-13 22:49:01 +02003852/* analog capture with dynamic dual-adc changes */
3853static int dualmic_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
3854 struct hda_codec *codec,
3855 unsigned int stream_tag,
3856 unsigned int format,
3857 struct snd_pcm_substream *substream)
3858{
3859 struct alc_spec *spec = codec->spec;
3860 spec->cur_adc = spec->adc_nids[spec->cur_adc_idx];
3861 spec->cur_adc_stream_tag = stream_tag;
3862 spec->cur_adc_format = format;
3863 snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
3864 return 0;
3865}
3866
3867static int dualmic_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
3868 struct hda_codec *codec,
3869 struct snd_pcm_substream *substream)
3870{
3871 struct alc_spec *spec = codec->spec;
3872 snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
3873 spec->cur_adc = 0;
3874 return 0;
3875}
3876
3877static struct hda_pcm_stream dualmic_pcm_analog_capture = {
3878 .substreams = 1,
3879 .channels_min = 2,
3880 .channels_max = 2,
3881 .nid = 0, /* fill later */
3882 .ops = {
3883 .prepare = dualmic_capture_pcm_prepare,
3884 .cleanup = dualmic_capture_pcm_cleanup
3885 },
3886};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003887
3888/*
3889 */
3890static struct hda_pcm_stream alc880_pcm_analog_playback = {
3891 .substreams = 1,
3892 .channels_min = 2,
3893 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003894 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895 .ops = {
3896 .open = alc880_playback_pcm_open,
3897 .prepare = alc880_playback_pcm_prepare,
3898 .cleanup = alc880_playback_pcm_cleanup
3899 },
3900};
3901
3902static struct hda_pcm_stream alc880_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01003903 .substreams = 1,
3904 .channels_min = 2,
3905 .channels_max = 2,
3906 /* NID is set in alc_build_pcms */
3907};
3908
3909static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
3910 .substreams = 1,
3911 .channels_min = 2,
3912 .channels_max = 2,
3913 /* NID is set in alc_build_pcms */
3914};
3915
3916static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
3917 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003918 .channels_min = 2,
3919 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003920 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003921 .ops = {
Takashi Iwai63300792008-01-24 15:31:36 +01003922 .prepare = alc880_alt_capture_pcm_prepare,
3923 .cleanup = alc880_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924 },
3925};
3926
3927static struct hda_pcm_stream alc880_pcm_digital_playback = {
3928 .substreams = 1,
3929 .channels_min = 2,
3930 .channels_max = 2,
3931 /* NID is set in alc_build_pcms */
3932 .ops = {
3933 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02003934 .close = alc880_dig_playback_pcm_close,
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01003935 .prepare = alc880_dig_playback_pcm_prepare,
3936 .cleanup = alc880_dig_playback_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937 },
3938};
3939
3940static struct hda_pcm_stream alc880_pcm_digital_capture = {
3941 .substreams = 1,
3942 .channels_min = 2,
3943 .channels_max = 2,
3944 /* NID is set in alc_build_pcms */
3945};
3946
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003947/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwai63300792008-01-24 15:31:36 +01003948static struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003949 .substreams = 0,
3950 .channels_min = 0,
3951 .channels_max = 0,
3952};
3953
Linus Torvalds1da177e2005-04-16 15:20:36 -07003954static int alc_build_pcms(struct hda_codec *codec)
3955{
3956 struct alc_spec *spec = codec->spec;
3957 struct hda_pcm *info = spec->pcm_rec;
3958 int i;
3959
3960 codec->num_pcms = 1;
3961 codec->pcm_info = info;
3962
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003963 if (spec->no_analog)
3964 goto skip_analog;
3965
Takashi Iwai812a2cc2009-05-16 10:00:49 +02003966 snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog),
3967 "%s Analog", codec->chip_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968 info->name = spec->stream_name_analog;
Kailang Yang274693f2009-12-03 10:07:50 +01003969
Takashi Iwai4a471b72005-12-07 13:56:29 +01003970 if (spec->stream_analog_playback) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02003971 if (snd_BUG_ON(!spec->multiout.dac_nids))
3972 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003973 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
3974 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
3975 }
3976 if (spec->stream_analog_capture) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02003977 if (snd_BUG_ON(!spec->adc_nids))
3978 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003979 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
3980 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
3981 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982
Takashi Iwai4a471b72005-12-07 13:56:29 +01003983 if (spec->channel_mode) {
3984 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
3985 for (i = 0; i < spec->num_channel_mode; i++) {
3986 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
3987 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
3988 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989 }
3990 }
3991
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003992 skip_analog:
Takashi Iwaie08a0072006-09-07 17:52:14 +02003993 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwai812a2cc2009-05-16 10:00:49 +02003995 snprintf(spec->stream_name_digital,
3996 sizeof(spec->stream_name_digital),
3997 "%s Digital", codec->chip_name);
Takashi Iwaie08a0072006-09-07 17:52:14 +02003998 codec->num_pcms = 2;
Wu Fengguangb25c9da2009-02-06 15:02:27 +08003999 codec->slave_dig_outs = spec->multiout.slave_dig_outs;
Takashi Iwaic06134d2006-10-11 18:49:13 +02004000 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004001 info->name = spec->stream_name_digital;
Takashi Iwai8c441982009-01-20 18:30:20 +01004002 if (spec->dig_out_type)
4003 info->pcm_type = spec->dig_out_type;
4004 else
4005 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004006 if (spec->multiout.dig_out_nid &&
4007 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
4009 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
4010 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01004011 if (spec->dig_in_nid &&
4012 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
4014 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
4015 }
Takashi Iwai963f8032008-08-11 10:04:40 +02004016 /* FIXME: do we need this for all Realtek codec models? */
4017 codec->spdif_status_reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018 }
4019
Takashi Iwaie64f14f2009-01-20 18:32:55 +01004020 if (spec->no_analog)
4021 return 0;
4022
Takashi Iwaie08a0072006-09-07 17:52:14 +02004023 /* If the use of more than one ADC is requested for the current
4024 * model, configure a second analog capture-only PCM.
4025 */
4026 /* Additional Analaog capture for index #2 */
Takashi Iwai63300792008-01-24 15:31:36 +01004027 if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
4028 (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02004029 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02004030 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02004031 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01004032 if (spec->alt_dac_nid) {
4033 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
4034 *spec->stream_analog_alt_playback;
4035 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
4036 spec->alt_dac_nid;
4037 } else {
4038 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
4039 alc_pcm_null_stream;
4040 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
4041 }
4042 if (spec->num_adc_nids > 1) {
4043 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
4044 *spec->stream_analog_alt_capture;
4045 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
4046 spec->adc_nids[1];
4047 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
4048 spec->num_adc_nids - 1;
4049 } else {
4050 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
4051 alc_pcm_null_stream;
4052 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02004053 }
4054 }
4055
Linus Torvalds1da177e2005-04-16 15:20:36 -07004056 return 0;
4057}
4058
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004059static inline void alc_shutup(struct hda_codec *codec)
4060{
4061 snd_hda_shutup_pins(codec);
4062}
4063
Takashi Iwai603c4012008-07-30 15:01:44 +02004064static void alc_free_kctls(struct hda_codec *codec)
4065{
4066 struct alc_spec *spec = codec->spec;
4067
4068 if (spec->kctls.list) {
4069 struct snd_kcontrol_new *kctl = spec->kctls.list;
4070 int i;
4071 for (i = 0; i < spec->kctls.used; i++)
4072 kfree(kctl[i].name);
4073 }
4074 snd_array_free(&spec->kctls);
4075}
4076
Linus Torvalds1da177e2005-04-16 15:20:36 -07004077static void alc_free(struct hda_codec *codec)
4078{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004079 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004080
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004081 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004082 return;
4083
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004084 alc_shutup(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +02004085 alc_free_kctls(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004086 kfree(spec);
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09004087 snd_hda_detach_beep_device(codec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004088}
4089
Hector Martinf5de24b2009-12-20 22:51:31 +01004090#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -05004091static void alc_power_eapd(struct hda_codec *codec)
4092{
4093 /* We currently only handle front, HP */
4094 switch (codec->vendor_id) {
4095 case 0x10ec0260:
Takashi Iwai9e4c8492010-01-19 15:53:43 +01004096 set_eapd(codec, 0x0f, 0);
4097 set_eapd(codec, 0x10, 0);
Daniel T Chenc97259d2009-12-27 18:52:08 -05004098 break;
4099 case 0x10ec0262:
4100 case 0x10ec0267:
4101 case 0x10ec0268:
4102 case 0x10ec0269:
Takashi Iwai9e4c8492010-01-19 15:53:43 +01004103 case 0x10ec0270:
Daniel T Chenc97259d2009-12-27 18:52:08 -05004104 case 0x10ec0272:
4105 case 0x10ec0660:
4106 case 0x10ec0662:
4107 case 0x10ec0663:
4108 case 0x10ec0862:
4109 case 0x10ec0889:
Takashi Iwai9e4c8492010-01-19 15:53:43 +01004110 set_eapd(codec, 0x14, 0);
4111 set_eapd(codec, 0x15, 0);
Daniel T Chenc97259d2009-12-27 18:52:08 -05004112 break;
4113 }
4114}
4115
Hector Martinf5de24b2009-12-20 22:51:31 +01004116static int alc_suspend(struct hda_codec *codec, pm_message_t state)
4117{
4118 struct alc_spec *spec = codec->spec;
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004119 alc_shutup(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01004120 if (spec && spec->power_hook)
Daniel T Chenc97259d2009-12-27 18:52:08 -05004121 spec->power_hook(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01004122 return 0;
4123}
4124#endif
4125
Takashi Iwaie044c392008-10-27 16:56:24 +01004126#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaie044c392008-10-27 16:56:24 +01004127static int alc_resume(struct hda_codec *codec)
4128{
Takashi Iwaie044c392008-10-27 16:56:24 +01004129 codec->patch_ops.init(codec);
4130 snd_hda_codec_resume_amp(codec);
4131 snd_hda_codec_resume_cache(codec);
Takashi Iwai9e5341b2010-09-21 09:57:06 +02004132 hda_call_check_power_status(codec, 0x01);
Takashi Iwaie044c392008-10-27 16:56:24 +01004133 return 0;
4134}
Takashi Iwaie044c392008-10-27 16:56:24 +01004135#endif
4136
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137/*
4138 */
4139static struct hda_codec_ops alc_patch_ops = {
4140 .build_controls = alc_build_controls,
4141 .build_pcms = alc_build_pcms,
4142 .init = alc_init,
4143 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004144 .unsol_event = alc_unsol_event,
Takashi Iwaie044c392008-10-27 16:56:24 +01004145#ifdef SND_HDA_NEEDS_RESUME
4146 .resume = alc_resume,
4147#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02004148#ifdef CONFIG_SND_HDA_POWER_SAVE
Hector Martinf5de24b2009-12-20 22:51:31 +01004149 .suspend = alc_suspend,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004150 .check_power_status = alc_check_power_status,
4151#endif
Daniel T Chenc97259d2009-12-27 18:52:08 -05004152 .reboot_notify = alc_shutup,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004153};
4154
Kailang Yangc027ddc2010-03-19 11:33:06 +01004155/* replace the codec chip_name with the given string */
4156static int alc_codec_rename(struct hda_codec *codec, const char *name)
4157{
4158 kfree(codec->chip_name);
4159 codec->chip_name = kstrdup(name, GFP_KERNEL);
4160 if (!codec->chip_name) {
4161 alc_free(codec);
4162 return -ENOMEM;
4163 }
4164 return 0;
4165}
4166
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004167/*
4168 * Test configuration for debugging
4169 *
4170 * Almost all inputs/outputs are enabled. I/O pins can be configured via
4171 * enum controls.
4172 */
4173#ifdef CONFIG_SND_DEBUG
4174static hda_nid_t alc880_test_dac_nids[4] = {
4175 0x02, 0x03, 0x04, 0x05
4176};
4177
4178static struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004179 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004180 .items = {
4181 { "In-1", 0x0 },
4182 { "In-2", 0x1 },
4183 { "In-3", 0x2 },
4184 { "In-4", 0x3 },
4185 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004186 { "Front", 0x5 },
4187 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004188 },
4189};
4190
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01004191static struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004192 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02004193 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004194 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02004195 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004196};
4197
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004198static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
4199 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004200{
4201 static char *texts[] = {
4202 "N/A", "Line Out", "HP Out",
4203 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
4204 };
4205 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
4206 uinfo->count = 1;
4207 uinfo->value.enumerated.items = 8;
4208 if (uinfo->value.enumerated.item >= 8)
4209 uinfo->value.enumerated.item = 7;
4210 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
4211 return 0;
4212}
4213
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004214static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
4215 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004216{
4217 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4218 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4219 unsigned int pin_ctl, item = 0;
4220
4221 pin_ctl = snd_hda_codec_read(codec, nid, 0,
4222 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
4223 if (pin_ctl & AC_PINCTL_OUT_EN) {
4224 if (pin_ctl & AC_PINCTL_HP_EN)
4225 item = 2;
4226 else
4227 item = 1;
4228 } else if (pin_ctl & AC_PINCTL_IN_EN) {
4229 switch (pin_ctl & AC_PINCTL_VREFEN) {
4230 case AC_PINCTL_VREF_HIZ: item = 3; break;
4231 case AC_PINCTL_VREF_50: item = 4; break;
4232 case AC_PINCTL_VREF_GRD: item = 5; break;
4233 case AC_PINCTL_VREF_80: item = 6; break;
4234 case AC_PINCTL_VREF_100: item = 7; break;
4235 }
4236 }
4237 ucontrol->value.enumerated.item[0] = item;
4238 return 0;
4239}
4240
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004241static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
4242 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004243{
4244 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4245 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4246 static unsigned int ctls[] = {
4247 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
4248 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
4249 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
4250 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
4251 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
4252 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
4253 };
4254 unsigned int old_ctl, new_ctl;
4255
4256 old_ctl = snd_hda_codec_read(codec, nid, 0,
4257 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
4258 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
4259 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004260 int val;
4261 snd_hda_codec_write_cache(codec, nid, 0,
4262 AC_VERB_SET_PIN_WIDGET_CONTROL,
4263 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02004264 val = ucontrol->value.enumerated.item[0] >= 3 ?
4265 HDA_AMP_MUTE : 0;
4266 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
4267 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004268 return 1;
4269 }
4270 return 0;
4271}
4272
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004273static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
4274 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004275{
4276 static char *texts[] = {
4277 "Front", "Surround", "CLFE", "Side"
4278 };
4279 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
4280 uinfo->count = 1;
4281 uinfo->value.enumerated.items = 4;
4282 if (uinfo->value.enumerated.item >= 4)
4283 uinfo->value.enumerated.item = 3;
4284 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
4285 return 0;
4286}
4287
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004288static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
4289 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004290{
4291 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4292 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4293 unsigned int sel;
4294
4295 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
4296 ucontrol->value.enumerated.item[0] = sel & 3;
4297 return 0;
4298}
4299
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004300static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
4301 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004302{
4303 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4304 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4305 unsigned int sel;
4306
4307 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
4308 if (ucontrol->value.enumerated.item[0] != sel) {
4309 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004310 snd_hda_codec_write_cache(codec, nid, 0,
4311 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004312 return 1;
4313 }
4314 return 0;
4315}
4316
4317#define PIN_CTL_TEST(xname,nid) { \
4318 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
4319 .name = xname, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01004320 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004321 .info = alc_test_pin_ctl_info, \
4322 .get = alc_test_pin_ctl_get, \
4323 .put = alc_test_pin_ctl_put, \
4324 .private_value = nid \
4325 }
4326
4327#define PIN_SRC_TEST(xname,nid) { \
4328 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
4329 .name = xname, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01004330 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004331 .info = alc_test_pin_src_info, \
4332 .get = alc_test_pin_src_get, \
4333 .put = alc_test_pin_src_put, \
4334 .private_value = nid \
4335 }
4336
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004337static struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02004338 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
4339 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
4340 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
4341 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004342 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
4343 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
4344 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
4345 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004346 PIN_CTL_TEST("Front Pin Mode", 0x14),
4347 PIN_CTL_TEST("Surround Pin Mode", 0x15),
4348 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
4349 PIN_CTL_TEST("Side Pin Mode", 0x17),
4350 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
4351 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
4352 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
4353 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
4354 PIN_SRC_TEST("In-1 Pin Source", 0x18),
4355 PIN_SRC_TEST("In-2 Pin Source", 0x19),
4356 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
4357 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
4358 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
4359 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
4360 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
4361 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
4362 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
4363 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
4364 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
4365 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
4366 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
4367 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004368 {
4369 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4370 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01004371 .info = alc_ch_mode_info,
4372 .get = alc_ch_mode_get,
4373 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004374 },
4375 { } /* end */
4376};
4377
4378static struct hda_verb alc880_test_init_verbs[] = {
4379 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02004380 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4381 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4382 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4383 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4384 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4385 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4386 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4387 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004388 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02004389 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4390 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4391 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4392 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004393 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004394 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4395 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4396 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4397 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004398 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004399 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4400 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4401 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4402 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004403 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02004404 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4405 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02004406 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4407 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4408 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004409 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02004410 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4411 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4412 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4413 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004414 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02004415 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004416 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004417 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004418 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004419 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004420 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004421 /* Analog input/passthru */
4422 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4423 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4424 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4425 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4426 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004427 { }
4428};
4429#endif
4430
Linus Torvalds1da177e2005-04-16 15:20:36 -07004431/*
4432 */
4433
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004434static const char *alc880_models[ALC880_MODEL_LAST] = {
4435 [ALC880_3ST] = "3stack",
4436 [ALC880_TCL_S700] = "tcl",
4437 [ALC880_3ST_DIG] = "3stack-digout",
4438 [ALC880_CLEVO] = "clevo",
4439 [ALC880_5ST] = "5stack",
4440 [ALC880_5ST_DIG] = "5stack-digout",
4441 [ALC880_W810] = "w810",
4442 [ALC880_Z71V] = "z71v",
4443 [ALC880_6ST] = "6stack",
4444 [ALC880_6ST_DIG] = "6stack-digout",
4445 [ALC880_ASUS] = "asus",
4446 [ALC880_ASUS_W1V] = "asus-w1v",
4447 [ALC880_ASUS_DIG] = "asus-dig",
4448 [ALC880_ASUS_DIG2] = "asus-dig2",
4449 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004450 [ALC880_UNIWILL_P53] = "uniwill-p53",
4451 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004452 [ALC880_F1734] = "F1734",
4453 [ALC880_LG] = "lg",
4454 [ALC880_LG_LW] = "lg-lw",
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004455 [ALC880_MEDION_RIM] = "medion",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004456#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004457 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004458#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004459 [ALC880_AUTO] = "auto",
4460};
4461
4462static struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004463 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004464 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
4465 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
4466 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
4467 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
4468 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
4469 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
4470 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
4471 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004472 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
4473 SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004474 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
4475 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
4476 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
4477 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
4478 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
4479 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
4480 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
4481 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
4482 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
4483 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Travis Place186c3112008-05-20 11:54:41 +02004484 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004485 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
4486 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
4487 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004488 SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004489 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004490 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
4491 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004492 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
4493 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004494 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
4495 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
4496 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
4497 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004498 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
4499 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004500 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004501 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004502 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004503 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004504 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
4505 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004506 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004507 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004508 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004509 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004510 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Travis Place1d116042008-06-23 11:42:30 +02004511 SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
Daniel T Chen33535412010-04-22 07:15:26 -04004512 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_F1734),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004513 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004514 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004515 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
4516 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004517 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004518 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
4519 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
4520 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
4521 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004522 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
4523 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004524 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004525 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004526 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
4527 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004528 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
4529 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
4530 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004531 /* default Intel */
4532 SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004533 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
4534 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535 {}
4536};
4537
Takashi Iwai16ded522005-06-10 19:58:24 +02004538/*
Kailang Yangdf694da2005-12-05 19:42:22 +01004539 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02004540 */
Takashi Iwai16ded522005-06-10 19:58:24 +02004541static struct alc_config_preset alc880_presets[] = {
4542 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004543 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004544 .init_verbs = { alc880_volume_init_verbs,
4545 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004546 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02004547 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004548 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4549 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004550 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004551 .input_mux = &alc880_capture_source,
4552 },
4553 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004554 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004555 .init_verbs = { alc880_volume_init_verbs,
4556 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004557 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02004558 .dac_nids = alc880_dac_nids,
4559 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004560 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4561 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004562 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004563 .input_mux = &alc880_capture_source,
4564 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004565 [ALC880_TCL_S700] = {
4566 .mixers = { alc880_tcl_s700_mixer },
4567 .init_verbs = { alc880_volume_init_verbs,
4568 alc880_pin_tcl_S700_init_verbs,
4569 alc880_gpio2_init_verbs },
4570 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4571 .dac_nids = alc880_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004572 .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */
4573 .num_adc_nids = 1, /* single ADC */
Kailang Yangdf694da2005-12-05 19:42:22 +01004574 .hp_nid = 0x03,
4575 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4576 .channel_mode = alc880_2_jack_modes,
4577 .input_mux = &alc880_capture_source,
4578 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004579 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004580 .mixers = { alc880_three_stack_mixer,
4581 alc880_five_stack_mixer},
4582 .init_verbs = { alc880_volume_init_verbs,
4583 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004584 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4585 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004586 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
4587 .channel_mode = alc880_fivestack_modes,
4588 .input_mux = &alc880_capture_source,
4589 },
4590 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004591 .mixers = { alc880_three_stack_mixer,
4592 alc880_five_stack_mixer },
4593 .init_verbs = { alc880_volume_init_verbs,
4594 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004595 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4596 .dac_nids = alc880_dac_nids,
4597 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004598 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
4599 .channel_mode = alc880_fivestack_modes,
4600 .input_mux = &alc880_capture_source,
4601 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02004602 [ALC880_6ST] = {
4603 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004604 .init_verbs = { alc880_volume_init_verbs,
4605 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02004606 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
4607 .dac_nids = alc880_6st_dac_nids,
4608 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
4609 .channel_mode = alc880_sixstack_modes,
4610 .input_mux = &alc880_6stack_capture_source,
4611 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004612 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004613 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004614 .init_verbs = { alc880_volume_init_verbs,
4615 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004616 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
4617 .dac_nids = alc880_6st_dac_nids,
4618 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004619 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
4620 .channel_mode = alc880_sixstack_modes,
4621 .input_mux = &alc880_6stack_capture_source,
4622 },
4623 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004624 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004625 .init_verbs = { alc880_volume_init_verbs,
4626 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02004627 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004628 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
4629 .dac_nids = alc880_w810_dac_nids,
4630 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004631 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
4632 .channel_mode = alc880_w810_modes,
4633 .input_mux = &alc880_capture_source,
4634 },
4635 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004636 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004637 .init_verbs = { alc880_volume_init_verbs,
4638 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004639 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
4640 .dac_nids = alc880_z71v_dac_nids,
4641 .dig_out_nid = ALC880_DIGOUT_NID,
4642 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004643 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4644 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02004645 .input_mux = &alc880_capture_source,
4646 },
4647 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004648 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004649 .init_verbs = { alc880_volume_init_verbs,
4650 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004651 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
4652 .dac_nids = alc880_f1734_dac_nids,
4653 .hp_nid = 0x02,
4654 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4655 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01004656 .input_mux = &alc880_f1734_capture_source,
4657 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004658 .setup = alc880_uniwill_p53_setup,
4659 .init_hook = alc_automute_amp,
Takashi Iwai16ded522005-06-10 19:58:24 +02004660 },
4661 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004662 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004663 .init_verbs = { alc880_volume_init_verbs,
4664 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004665 alc880_gpio1_init_verbs },
4666 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4667 .dac_nids = alc880_asus_dac_nids,
4668 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4669 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004670 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004671 .input_mux = &alc880_capture_source,
4672 },
4673 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004674 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004675 .init_verbs = { alc880_volume_init_verbs,
4676 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004677 alc880_gpio1_init_verbs },
4678 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4679 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004680 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004681 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4682 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004683 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004684 .input_mux = &alc880_capture_source,
4685 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004686 [ALC880_ASUS_DIG2] = {
4687 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004688 .init_verbs = { alc880_volume_init_verbs,
4689 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01004690 alc880_gpio2_init_verbs }, /* use GPIO2 */
4691 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4692 .dac_nids = alc880_asus_dac_nids,
4693 .dig_out_nid = ALC880_DIGOUT_NID,
4694 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4695 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004696 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01004697 .input_mux = &alc880_capture_source,
4698 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004699 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004700 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004701 .init_verbs = { alc880_volume_init_verbs,
4702 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004703 alc880_gpio1_init_verbs },
4704 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4705 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004706 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004707 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4708 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004709 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004710 .input_mux = &alc880_capture_source,
4711 },
4712 [ALC880_UNIWILL_DIG] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004713 .mixers = { alc880_asus_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02004714 .init_verbs = { alc880_volume_init_verbs,
4715 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004716 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4717 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004718 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004719 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4720 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004721 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004722 .input_mux = &alc880_capture_source,
4723 },
Kailang Yangccc656c2006-10-17 12:32:26 +02004724 [ALC880_UNIWILL] = {
4725 .mixers = { alc880_uniwill_mixer },
4726 .init_verbs = { alc880_volume_init_verbs,
4727 alc880_uniwill_init_verbs },
4728 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4729 .dac_nids = alc880_asus_dac_nids,
4730 .dig_out_nid = ALC880_DIGOUT_NID,
4731 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4732 .channel_mode = alc880_threestack_modes,
4733 .need_dac_fix = 1,
4734 .input_mux = &alc880_capture_source,
4735 .unsol_event = alc880_uniwill_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004736 .setup = alc880_uniwill_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004737 .init_hook = alc880_uniwill_init_hook,
Kailang Yangccc656c2006-10-17 12:32:26 +02004738 },
4739 [ALC880_UNIWILL_P53] = {
4740 .mixers = { alc880_uniwill_p53_mixer },
4741 .init_verbs = { alc880_volume_init_verbs,
4742 alc880_uniwill_p53_init_verbs },
4743 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4744 .dac_nids = alc880_asus_dac_nids,
4745 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004746 .channel_mode = alc880_threestack_modes,
4747 .input_mux = &alc880_capture_source,
4748 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004749 .setup = alc880_uniwill_p53_setup,
4750 .init_hook = alc_automute_amp,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004751 },
4752 [ALC880_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004753 .mixers = { alc880_fujitsu_mixer },
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004754 .init_verbs = { alc880_volume_init_verbs,
4755 alc880_uniwill_p53_init_verbs,
4756 alc880_beep_init_verbs },
4757 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4758 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02004759 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004760 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4761 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02004762 .input_mux = &alc880_capture_source,
4763 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004764 .setup = alc880_uniwill_p53_setup,
4765 .init_hook = alc_automute_amp,
Kailang Yangccc656c2006-10-17 12:32:26 +02004766 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004767 [ALC880_CLEVO] = {
4768 .mixers = { alc880_three_stack_mixer },
4769 .init_verbs = { alc880_volume_init_verbs,
4770 alc880_pin_clevo_init_verbs },
4771 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4772 .dac_nids = alc880_dac_nids,
4773 .hp_nid = 0x03,
4774 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4775 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004776 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01004777 .input_mux = &alc880_capture_source,
4778 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004779 [ALC880_LG] = {
4780 .mixers = { alc880_lg_mixer },
4781 .init_verbs = { alc880_volume_init_verbs,
4782 alc880_lg_init_verbs },
4783 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
4784 .dac_nids = alc880_lg_dac_nids,
4785 .dig_out_nid = ALC880_DIGOUT_NID,
4786 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
4787 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004788 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004789 .input_mux = &alc880_lg_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004790 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004791 .setup = alc880_lg_setup,
4792 .init_hook = alc_automute_amp,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004793#ifdef CONFIG_SND_HDA_POWER_SAVE
4794 .loopbacks = alc880_lg_loopbacks,
4795#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004796 },
Takashi Iwaid6815182006-03-23 16:06:23 +01004797 [ALC880_LG_LW] = {
4798 .mixers = { alc880_lg_lw_mixer },
4799 .init_verbs = { alc880_volume_init_verbs,
4800 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004801 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01004802 .dac_nids = alc880_dac_nids,
4803 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004804 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
4805 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01004806 .input_mux = &alc880_lg_lw_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004807 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004808 .setup = alc880_lg_lw_setup,
4809 .init_hook = alc_automute_amp,
Takashi Iwaid6815182006-03-23 16:06:23 +01004810 },
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004811 [ALC880_MEDION_RIM] = {
4812 .mixers = { alc880_medion_rim_mixer },
4813 .init_verbs = { alc880_volume_init_verbs,
4814 alc880_medion_rim_init_verbs,
4815 alc_gpio2_init_verbs },
4816 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4817 .dac_nids = alc880_dac_nids,
4818 .dig_out_nid = ALC880_DIGOUT_NID,
4819 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4820 .channel_mode = alc880_2_jack_modes,
4821 .input_mux = &alc880_medion_rim_capture_source,
4822 .unsol_event = alc880_medion_rim_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004823 .setup = alc880_medion_rim_setup,
4824 .init_hook = alc880_medion_rim_automute,
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004825 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004826#ifdef CONFIG_SND_DEBUG
4827 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004828 .mixers = { alc880_test_mixer },
4829 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004830 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
4831 .dac_nids = alc880_test_dac_nids,
4832 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004833 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
4834 .channel_mode = alc880_test_modes,
4835 .input_mux = &alc880_test_capture_source,
4836 },
4837#endif
4838};
4839
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004840/*
4841 * Automatic parse of I/O pins from the BIOS configuration
4842 */
4843
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004844enum {
4845 ALC_CTL_WIDGET_VOL,
4846 ALC_CTL_WIDGET_MUTE,
4847 ALC_CTL_BIND_MUTE,
4848};
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004849static struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004850 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
4851 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01004852 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004853};
4854
4855/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004856static int add_control(struct alc_spec *spec, int type, const char *name,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02004857 int cidx, unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004858{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004859 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004860
Takashi Iwai603c4012008-07-30 15:01:44 +02004861 snd_array_init(&spec->kctls, sizeof(*knew), 32);
4862 knew = snd_array_new(&spec->kctls);
4863 if (!knew)
4864 return -ENOMEM;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004865 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07004866 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004867 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004868 return -ENOMEM;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02004869 knew->index = cidx;
Jaroslav Kysela4d02d1b2009-11-12 10:15:48 +01004870 if (get_amp_nid_(val))
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01004871 knew->subdevice = HDA_SUBDEV_AMP_FLAG;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004872 knew->private_value = val;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004873 return 0;
4874}
4875
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004876static int add_control_with_pfx(struct alc_spec *spec, int type,
4877 const char *pfx, const char *dir,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02004878 const char *sfx, int cidx, unsigned long val)
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004879{
4880 char name[32];
4881 snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
Takashi Iwai66ceeb62010-08-30 13:05:52 +02004882 return add_control(spec, type, name, cidx, val);
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004883}
4884
Takashi Iwai66ceeb62010-08-30 13:05:52 +02004885#define add_pb_vol_ctrl(spec, type, pfx, val) \
4886 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
4887#define add_pb_sw_ctrl(spec, type, pfx, val) \
4888 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
4889#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \
4890 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
4891#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \
4892 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004893
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004894#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
4895#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
4896#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
4897#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004898#define alc880_idx_to_dac(nid) ((nid) + 0x02)
4899#define alc880_dac_to_idx(nid) ((nid) - 0x02)
4900#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
4901#define alc880_idx_to_selector(nid) ((nid) + 0x10)
4902#define ALC880_PIN_CD_NID 0x1c
4903
4904/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004905static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
4906 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004907{
4908 hda_nid_t nid;
4909 int assigned[4];
4910 int i, j;
4911
4912 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02004913 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004914
4915 /* check the pins hardwired to audio widget */
4916 for (i = 0; i < cfg->line_outs; i++) {
4917 nid = cfg->line_out_pins[i];
4918 if (alc880_is_fixed_pin(nid)) {
4919 int idx = alc880_fixed_pin_idx(nid);
Libin Yang5014f192005-11-23 15:48:36 +01004920 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004921 assigned[idx] = 1;
4922 }
4923 }
4924 /* left pins can be connect to any audio widget */
4925 for (i = 0; i < cfg->line_outs; i++) {
4926 nid = cfg->line_out_pins[i];
4927 if (alc880_is_fixed_pin(nid))
4928 continue;
4929 /* search for an empty channel */
4930 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004931 if (!assigned[j]) {
4932 spec->multiout.dac_nids[i] =
4933 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004934 assigned[j] = 1;
4935 break;
4936 }
4937 }
4938 }
4939 spec->multiout.num_dacs = cfg->line_outs;
4940 return 0;
4941}
4942
4943/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01004944static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
4945 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004946{
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004947 static const char *chname[4] = {
4948 "Front", "Surround", NULL /*CLFE*/, "Side"
4949 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004950 hda_nid_t nid;
4951 int i, err;
4952
4953 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004954 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004955 continue;
4956 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
4957 if (i == 2) {
4958 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004959 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
4960 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004961 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
4962 HDA_OUTPUT));
4963 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004964 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004965 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
4966 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004967 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
4968 HDA_OUTPUT));
4969 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004970 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004971 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
4972 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004973 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
4974 HDA_INPUT));
4975 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004976 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004977 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
4978 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004979 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
4980 HDA_INPUT));
4981 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004982 return err;
4983 } else {
Takashi Iwaicb162b62009-08-25 16:05:03 +02004984 const char *pfx;
4985 if (cfg->line_outs == 1 &&
4986 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
4987 pfx = "Speaker";
4988 else
4989 pfx = chname[i];
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004990 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004991 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
4992 HDA_OUTPUT));
4993 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004994 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004995 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004996 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
4997 HDA_INPUT));
4998 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004999 return err;
5000 }
5001 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005002 return 0;
5003}
5004
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005005/* add playback controls for speaker and HP outputs */
5006static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
5007 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005008{
5009 hda_nid_t nid;
5010 int err;
5011
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005012 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005013 return 0;
5014
5015 if (alc880_is_fixed_pin(pin)) {
5016 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01005017 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005018 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005019 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01005020 else
5021 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005022 /* control HP volume/switch on the output mixer amp */
5023 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005024 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005025 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
5026 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005027 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005028 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005029 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
5030 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005031 return err;
5032 } else if (alc880_is_multi_pin(pin)) {
5033 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005034 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005035 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005036 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
5037 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005038 return err;
5039 }
5040 return 0;
5041}
5042
5043/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005044static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005045 const char *ctlname, int ctlidx,
Kailang Yangdf694da2005-12-05 19:42:22 +01005046 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005047{
Kailang Yangdf694da2005-12-05 19:42:22 +01005048 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005049
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005050 err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, ctlidx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005051 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
5052 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005053 return err;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005054 err = __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, ctlidx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005055 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
5056 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005057 return err;
5058 return 0;
5059}
5060
Takashi Iwai05f5f472009-08-25 13:10:18 +02005061static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005062{
Takashi Iwai05f5f472009-08-25 13:10:18 +02005063 unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
5064 return (pincap & AC_PINCAP_IN) != 0;
5065}
5066
5067/* create playback/capture controls for input pins */
5068static int alc_auto_create_input_ctls(struct hda_codec *codec,
5069 const struct auto_pin_cfg *cfg,
5070 hda_nid_t mixer,
5071 hda_nid_t cap1, hda_nid_t cap2)
5072{
5073 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005074 struct hda_input_mux *imux = &spec->private_imux[0];
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005075 int i, err, idx, type, type_idx = 0;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005076
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005077 for (i = 0; i < cfg->num_inputs; i++) {
Takashi Iwai05f5f472009-08-25 13:10:18 +02005078 hda_nid_t pin;
Takashi Iwai10a20af2010-09-09 16:28:02 +02005079 const char *label;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005080
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005081 pin = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005082 if (!alc_is_input_pin(codec, pin))
5083 continue;
5084
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005085 type = cfg->inputs[i].type;
5086 if (i > 0 && type == cfg->inputs[i - 1].type)
5087 type_idx++;
5088 else
5089 type_idx = 0;
Takashi Iwai10a20af2010-09-09 16:28:02 +02005090 label = hda_get_autocfg_input_label(codec, cfg, i);
Takashi Iwai05f5f472009-08-25 13:10:18 +02005091 if (mixer) {
5092 idx = get_connection_index(codec, mixer, pin);
5093 if (idx >= 0) {
5094 err = new_analog_input(spec, pin,
Takashi Iwai10a20af2010-09-09 16:28:02 +02005095 label, type_idx,
5096 idx, mixer);
Takashi Iwai05f5f472009-08-25 13:10:18 +02005097 if (err < 0)
5098 return err;
5099 }
5100 }
5101
5102 if (!cap1)
5103 continue;
5104 idx = get_connection_index(codec, cap1, pin);
5105 if (idx < 0 && cap2)
5106 idx = get_connection_index(codec, cap2, pin);
Takashi Iwai10a20af2010-09-09 16:28:02 +02005107 if (idx >= 0)
5108 snd_hda_add_imux_item(imux, label, idx, NULL);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005109 }
5110 return 0;
5111}
5112
Takashi Iwai05f5f472009-08-25 13:10:18 +02005113static int alc880_auto_create_input_ctls(struct hda_codec *codec,
5114 const struct auto_pin_cfg *cfg)
5115{
5116 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x08, 0x09);
5117}
5118
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005119static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
5120 unsigned int pin_type)
5121{
5122 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5123 pin_type);
5124 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01005125 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
5126 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005127}
5128
Kailang Yangdf694da2005-12-05 19:42:22 +01005129static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
5130 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005131 int dac_idx)
5132{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005133 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005134 /* need the manual connection? */
5135 if (alc880_is_multi_pin(nid)) {
5136 struct alc_spec *spec = codec->spec;
5137 int idx = alc880_multi_pin_idx(nid);
5138 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
5139 AC_VERB_SET_CONNECT_SEL,
5140 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
5141 }
5142}
5143
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005144static int get_pin_type(int line_out_type)
5145{
5146 if (line_out_type == AUTO_PIN_HP_OUT)
5147 return PIN_HP;
5148 else
5149 return PIN_OUT;
5150}
5151
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005152static void alc880_auto_init_multi_out(struct hda_codec *codec)
5153{
5154 struct alc_spec *spec = codec->spec;
5155 int i;
Kailang Yangea1fb292008-08-26 12:58:38 +02005156
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005157 for (i = 0; i < spec->autocfg.line_outs; i++) {
5158 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005159 int pin_type = get_pin_type(spec->autocfg.line_out_type);
5160 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005161 }
5162}
5163
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005164static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005165{
5166 struct alc_spec *spec = codec->spec;
5167 hda_nid_t pin;
5168
Takashi Iwai82bc9552006-03-21 11:24:42 +01005169 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005170 if (pin) /* connect to front */
5171 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005172 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005173 if (pin) /* connect to front */
5174 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
5175}
5176
5177static void alc880_auto_init_analog_input(struct hda_codec *codec)
5178{
5179 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005180 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005181 int i;
5182
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005183 for (i = 0; i < cfg->num_inputs; i++) {
5184 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005185 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai30ea0982010-09-16 18:47:56 +02005186 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwaie82c0252009-03-23 15:17:38 +01005187 if (nid != ALC880_PIN_CD_NID &&
5188 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005189 snd_hda_codec_write(codec, nid, 0,
5190 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005191 AMP_OUT_MUTE);
5192 }
5193 }
5194}
5195
Takashi Iwai7f311a42010-04-09 17:32:23 +02005196static void alc880_auto_init_input_src(struct hda_codec *codec)
5197{
5198 struct alc_spec *spec = codec->spec;
5199 int c;
5200
5201 for (c = 0; c < spec->num_adc_nids; c++) {
5202 unsigned int mux_idx;
5203 const struct hda_input_mux *imux;
5204 mux_idx = c >= spec->num_mux_defs ? 0 : c;
5205 imux = &spec->input_mux[mux_idx];
5206 if (!imux->num_items && mux_idx > 0)
5207 imux = &spec->input_mux[0];
5208 if (imux)
5209 snd_hda_codec_write(codec, spec->adc_nids[c], 0,
5210 AC_VERB_SET_CONNECT_SEL,
5211 imux->items[0].index);
5212 }
5213}
5214
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005215/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005216/* return 1 if successful, 0 if the proper config is not found,
5217 * or a negative error code
5218 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005219static int alc880_parse_auto_config(struct hda_codec *codec)
5220{
5221 struct alc_spec *spec = codec->spec;
Takashi Iwai757899a2010-07-30 10:48:14 +02005222 int err;
Kailang Yangdf694da2005-12-05 19:42:22 +01005223 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005224
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005225 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
5226 alc880_ignore);
5227 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005228 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005229 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005230 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01005231
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005232 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
5233 if (err < 0)
5234 return err;
5235 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
5236 if (err < 0)
5237 return err;
5238 err = alc880_auto_create_extra_out(spec,
5239 spec->autocfg.speaker_pins[0],
5240 "Speaker");
5241 if (err < 0)
5242 return err;
5243 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
5244 "Headphone");
5245 if (err < 0)
5246 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005247 err = alc880_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005248 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005249 return err;
5250
5251 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
5252
Takashi Iwai757899a2010-07-30 10:48:14 +02005253 alc_auto_parse_digital(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005254
Takashi Iwai603c4012008-07-30 15:01:44 +02005255 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01005256 add_mixer(spec, spec->kctls.list);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005257
Takashi Iwaid88897e2008-10-31 15:01:37 +01005258 add_verb(spec, alc880_volume_init_verbs);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005259
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005260 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005261 spec->input_mux = &spec->private_imux[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005262
Kailang Yang6227cdc2010-02-25 08:36:52 +01005263 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02005264
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005265 return 1;
5266}
5267
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005268/* additional initialization for auto-configuration model */
5269static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005270{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005271 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005272 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005273 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005274 alc880_auto_init_analog_input(codec);
Takashi Iwai7f311a42010-04-09 17:32:23 +02005275 alc880_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +02005276 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005277 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02005278 alc_inithook(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005279}
5280
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005281/* check the ADC/MUX contains all input pins; some ADC/MUX contains only
5282 * one of two digital mic pins, e.g. on ALC272
5283 */
5284static void fixup_automic_adc(struct hda_codec *codec)
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005285{
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005286 struct alc_spec *spec = codec->spec;
5287 int i;
5288
5289 for (i = 0; i < spec->num_adc_nids; i++) {
5290 hda_nid_t cap = spec->capsrc_nids ?
5291 spec->capsrc_nids[i] : spec->adc_nids[i];
5292 int iidx, eidx;
5293
5294 iidx = get_connection_index(codec, cap, spec->int_mic.pin);
5295 if (iidx < 0)
5296 continue;
5297 eidx = get_connection_index(codec, cap, spec->ext_mic.pin);
5298 if (eidx < 0)
5299 continue;
5300 spec->int_mic.mux_idx = iidx;
5301 spec->ext_mic.mux_idx = eidx;
5302 if (spec->capsrc_nids)
5303 spec->capsrc_nids += i;
5304 spec->adc_nids += i;
5305 spec->num_adc_nids = 1;
5306 return;
5307 }
5308 snd_printd(KERN_INFO "hda_codec: %s: "
5309 "No ADC/MUX containing both 0x%x and 0x%x pins\n",
5310 codec->chip_name, spec->int_mic.pin, spec->ext_mic.pin);
5311 spec->auto_mic = 0; /* disable auto-mic to be sure */
5312}
5313
Takashi Iwai748cce42010-08-04 07:37:39 +02005314/* select or unmute the given capsrc route */
5315static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap,
5316 int idx)
5317{
5318 if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
5319 snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
5320 HDA_AMP_MUTE, 0);
5321 } else {
5322 snd_hda_codec_write_cache(codec, cap, 0,
5323 AC_VERB_SET_CONNECT_SEL, idx);
5324 }
5325}
5326
Takashi Iwai840b64c2010-07-13 22:49:01 +02005327/* set the default connection to that pin */
5328static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
5329{
5330 struct alc_spec *spec = codec->spec;
5331 int i;
5332
5333 for (i = 0; i < spec->num_adc_nids; i++) {
5334 hda_nid_t cap = spec->capsrc_nids ?
5335 spec->capsrc_nids[i] : spec->adc_nids[i];
5336 int idx;
5337
5338 idx = get_connection_index(codec, cap, pin);
5339 if (idx < 0)
5340 continue;
Takashi Iwai748cce42010-08-04 07:37:39 +02005341 select_or_unmute_capsrc(codec, cap, idx);
Takashi Iwai840b64c2010-07-13 22:49:01 +02005342 return i; /* return the found index */
5343 }
5344 return -1; /* not found */
5345}
5346
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005347/* choose the ADC/MUX containing the input pin and initialize the setup */
5348static void fixup_single_adc(struct hda_codec *codec)
5349{
5350 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005351 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005352 int i;
5353
5354 /* search for the input pin; there must be only one */
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005355 if (cfg->num_inputs != 1)
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005356 return;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005357 i = init_capsrc_for_pin(codec, cfg->inputs[0].pin);
Takashi Iwai840b64c2010-07-13 22:49:01 +02005358 if (i >= 0) {
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005359 /* use only this ADC */
5360 if (spec->capsrc_nids)
5361 spec->capsrc_nids += i;
5362 spec->adc_nids += i;
5363 spec->num_adc_nids = 1;
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005364 }
5365}
5366
Takashi Iwai840b64c2010-07-13 22:49:01 +02005367/* initialize dual adcs */
5368static void fixup_dual_adc_switch(struct hda_codec *codec)
5369{
5370 struct alc_spec *spec = codec->spec;
5371 init_capsrc_for_pin(codec, spec->ext_mic.pin);
5372 init_capsrc_for_pin(codec, spec->int_mic.pin);
5373}
5374
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005375static void set_capture_mixer(struct hda_codec *codec)
5376{
5377 struct alc_spec *spec = codec->spec;
Takashi Iwaia23b6882009-03-23 15:21:36 +01005378 static struct snd_kcontrol_new *caps[2][3] = {
5379 { alc_capture_mixer_nosrc1,
5380 alc_capture_mixer_nosrc2,
5381 alc_capture_mixer_nosrc3 },
5382 { alc_capture_mixer1,
5383 alc_capture_mixer2,
5384 alc_capture_mixer3 },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005385 };
Takashi Iwaia23b6882009-03-23 15:21:36 +01005386 if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005387 int mux = 0;
Takashi Iwai840b64c2010-07-13 22:49:01 +02005388 int num_adcs = spec->num_adc_nids;
5389 if (spec->dual_adc_switch)
5390 fixup_dual_adc_switch(codec);
5391 else if (spec->auto_mic)
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005392 fixup_automic_adc(codec);
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005393 else if (spec->input_mux) {
5394 if (spec->input_mux->num_items > 1)
5395 mux = 1;
5396 else if (spec->input_mux->num_items == 1)
5397 fixup_single_adc(codec);
5398 }
Takashi Iwai840b64c2010-07-13 22:49:01 +02005399 if (spec->dual_adc_switch)
5400 num_adcs = 1;
5401 spec->cap_mixer = caps[mux][num_adcs - 1];
Takashi Iwaia23b6882009-03-23 15:21:36 +01005402 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005403}
5404
Takashi Iwai66946352010-03-29 17:21:45 +02005405/* fill adc_nids (and capsrc_nids) containing all active input pins */
5406static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids,
5407 int num_nids)
5408{
5409 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005410 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai66946352010-03-29 17:21:45 +02005411 int n;
5412 hda_nid_t fallback_adc = 0, fallback_cap = 0;
5413
5414 for (n = 0; n < num_nids; n++) {
5415 hda_nid_t adc, cap;
5416 hda_nid_t conn[HDA_MAX_NUM_INPUTS];
5417 int nconns, i, j;
5418
5419 adc = nids[n];
5420 if (get_wcaps_type(get_wcaps(codec, adc)) != AC_WID_AUD_IN)
5421 continue;
5422 cap = adc;
5423 nconns = snd_hda_get_connections(codec, cap, conn,
5424 ARRAY_SIZE(conn));
5425 if (nconns == 1) {
5426 cap = conn[0];
5427 nconns = snd_hda_get_connections(codec, cap, conn,
5428 ARRAY_SIZE(conn));
5429 }
5430 if (nconns <= 0)
5431 continue;
5432 if (!fallback_adc) {
5433 fallback_adc = adc;
5434 fallback_cap = cap;
5435 }
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005436 for (i = 0; i < cfg->num_inputs; i++) {
5437 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai66946352010-03-29 17:21:45 +02005438 for (j = 0; j < nconns; j++) {
5439 if (conn[j] == nid)
5440 break;
5441 }
5442 if (j >= nconns)
5443 break;
5444 }
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005445 if (i >= cfg->num_inputs) {
Takashi Iwai66946352010-03-29 17:21:45 +02005446 int num_adcs = spec->num_adc_nids;
5447 spec->private_adc_nids[num_adcs] = adc;
5448 spec->private_capsrc_nids[num_adcs] = cap;
5449 spec->num_adc_nids++;
5450 spec->adc_nids = spec->private_adc_nids;
5451 if (adc != cap)
5452 spec->capsrc_nids = spec->private_capsrc_nids;
5453 }
5454 }
5455 if (!spec->num_adc_nids) {
5456 printk(KERN_WARNING "hda_codec: %s: no valid ADC found;"
Takashi Iwai1f85d722010-03-30 07:48:05 +02005457 " using fallback 0x%x\n",
5458 codec->chip_name, fallback_adc);
Takashi Iwai66946352010-03-29 17:21:45 +02005459 spec->private_adc_nids[0] = fallback_adc;
5460 spec->adc_nids = spec->private_adc_nids;
5461 if (fallback_adc != fallback_cap) {
5462 spec->private_capsrc_nids[0] = fallback_cap;
5463 spec->capsrc_nids = spec->private_adc_nids;
5464 }
5465 }
5466}
5467
Takashi Iwai67d634c2009-11-16 15:35:59 +01005468#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005469#define set_beep_amp(spec, nid, idx, dir) \
5470 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005471
5472static struct snd_pci_quirk beep_white_list[] = {
5473 SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
Takashi Iwai080dc7b2010-09-08 08:38:41 +02005474 SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
Takashi Iwaie096c8e2010-08-03 17:20:35 +02005475 SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005476 {}
5477};
5478
5479static inline int has_cdefine_beep(struct hda_codec *codec)
5480{
5481 struct alc_spec *spec = codec->spec;
5482 const struct snd_pci_quirk *q;
5483 q = snd_pci_quirk_lookup(codec->bus->pci, beep_white_list);
5484 if (q)
5485 return q->value;
5486 return spec->cdefine.enable_pcbeep;
5487}
Takashi Iwai67d634c2009-11-16 15:35:59 +01005488#else
5489#define set_beep_amp(spec, nid, idx, dir) /* NOP */
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005490#define has_cdefine_beep(codec) 0
Takashi Iwai67d634c2009-11-16 15:35:59 +01005491#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005492
5493/*
5494 * OK, here we have finally the patch for ALC880
5495 */
5496
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497static int patch_alc880(struct hda_codec *codec)
5498{
5499 struct alc_spec *spec;
5500 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01005501 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005502
Takashi Iwaie560d8d2005-09-09 14:21:46 +02005503 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005504 if (spec == NULL)
5505 return -ENOMEM;
5506
5507 codec->spec = spec;
5508
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005509 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
5510 alc880_models,
5511 alc880_cfg_tbl);
5512 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02005513 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
5514 codec->chip_name);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005515 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005516 }
5517
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005518 if (board_config == ALC880_AUTO) {
5519 /* automatic parse from the BIOS config */
5520 err = alc880_parse_auto_config(codec);
5521 if (err < 0) {
5522 alc_free(codec);
5523 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005524 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005525 printk(KERN_INFO
5526 "hda_codec: Cannot set up configuration "
5527 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005528 board_config = ALC880_3ST;
5529 }
5530 }
5531
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09005532 err = snd_hda_attach_beep_device(codec, 0x1);
5533 if (err < 0) {
5534 alc_free(codec);
5535 return err;
5536 }
5537
Kailang Yangdf694da2005-12-05 19:42:22 +01005538 if (board_config != ALC880_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02005539 setup_preset(codec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005540
Linus Torvalds1da177e2005-04-16 15:20:36 -07005541 spec->stream_analog_playback = &alc880_pcm_analog_playback;
5542 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01005543 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005544
Linus Torvalds1da177e2005-04-16 15:20:36 -07005545 spec->stream_digital_playback = &alc880_pcm_digital_playback;
5546 spec->stream_digital_capture = &alc880_pcm_digital_capture;
5547
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005548 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005549 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01005550 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005551 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +02005552 wcap = get_wcaps_type(wcap);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005553 if (wcap != AC_WID_AUD_IN) {
5554 spec->adc_nids = alc880_adc_nids_alt;
5555 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005556 } else {
5557 spec->adc_nids = alc880_adc_nids;
5558 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005559 }
5560 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005561 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005562 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005563
Takashi Iwai2134ea42008-01-10 16:53:55 +01005564 spec->vmaster_nid = 0x0c;
5565
Linus Torvalds1da177e2005-04-16 15:20:36 -07005566 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005567 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005568 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02005569#ifdef CONFIG_SND_HDA_POWER_SAVE
5570 if (!spec->loopback.amplist)
5571 spec->loopback.amplist = alc880_loopbacks;
5572#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005573
5574 return 0;
5575}
5576
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005577
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578/*
5579 * ALC260 support
5580 */
5581
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005582static hda_nid_t alc260_dac_nids[1] = {
5583 /* front */
5584 0x02,
5585};
5586
5587static hda_nid_t alc260_adc_nids[1] = {
5588 /* ADC0 */
5589 0x04,
5590};
5591
Kailang Yangdf694da2005-12-05 19:42:22 +01005592static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005593 /* ADC1 */
5594 0x05,
5595};
5596
Jonathan Woithed57fdac2006-02-28 11:38:35 +01005597/* NIDs used when simultaneous access to both ADCs makes sense. Note that
5598 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
5599 */
5600static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005601 /* ADC0, ADC1 */
5602 0x04, 0x05
5603};
5604
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005605#define ALC260_DIGOUT_NID 0x03
5606#define ALC260_DIGIN_NID 0x06
5607
5608static struct hda_input_mux alc260_capture_source = {
5609 .num_items = 4,
5610 .items = {
5611 { "Mic", 0x0 },
5612 { "Front Mic", 0x1 },
5613 { "Line", 0x2 },
5614 { "CD", 0x4 },
5615 },
5616};
5617
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01005618/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005619 * headphone jack and the internal CD lines since these are the only pins at
5620 * which audio can appear. For flexibility, also allow the option of
5621 * recording the mixer output on the second ADC (ADC0 doesn't have a
5622 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005623 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005624static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
5625 {
5626 .num_items = 3,
5627 .items = {
5628 { "Mic/Line", 0x0 },
5629 { "CD", 0x4 },
5630 { "Headphone", 0x2 },
5631 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005632 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005633 {
5634 .num_items = 4,
5635 .items = {
5636 { "Mic/Line", 0x0 },
5637 { "CD", 0x4 },
5638 { "Headphone", 0x2 },
5639 { "Mixer", 0x5 },
5640 },
5641 },
5642
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005643};
5644
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005645/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
5646 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005647 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005648static struct hda_input_mux alc260_acer_capture_sources[2] = {
5649 {
5650 .num_items = 4,
5651 .items = {
5652 { "Mic", 0x0 },
5653 { "Line", 0x2 },
5654 { "CD", 0x4 },
5655 { "Headphone", 0x5 },
5656 },
5657 },
5658 {
5659 .num_items = 5,
5660 .items = {
5661 { "Mic", 0x0 },
5662 { "Line", 0x2 },
5663 { "CD", 0x4 },
5664 { "Headphone", 0x6 },
5665 { "Mixer", 0x5 },
5666 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005667 },
5668};
Michael Schwingencc959482009-02-22 18:58:45 +01005669
5670/* Maxdata Favorit 100XS */
5671static struct hda_input_mux alc260_favorit100_capture_sources[2] = {
5672 {
5673 .num_items = 2,
5674 .items = {
5675 { "Line/Mic", 0x0 },
5676 { "CD", 0x4 },
5677 },
5678 },
5679 {
5680 .num_items = 3,
5681 .items = {
5682 { "Line/Mic", 0x0 },
5683 { "CD", 0x4 },
5684 { "Mixer", 0x5 },
5685 },
5686 },
5687};
5688
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689/*
5690 * This is just place-holder, so there's something for alc_build_pcms to look
5691 * at when it calculates the maximum number of channels. ALC260 has no mixer
5692 * element which allows changing the channel mode, so the verb list is
5693 * never used.
5694 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01005695static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005696 { 2, NULL },
5697};
5698
Kailang Yangdf694da2005-12-05 19:42:22 +01005699
5700/* Mixer combinations
5701 *
5702 * basic: base_output + input + pc_beep + capture
5703 * HP: base_output + input + capture_alt
5704 * HP_3013: hp_3013 + input + capture
5705 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005706 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01005707 */
5708
5709static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02005710 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005711 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01005712 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5713 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
5714 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5715 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5716 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005717};
Kailang Yangdf694da2005-12-05 19:42:22 +01005718
5719static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005720 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5721 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5722 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5723 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5724 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5725 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5726 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
5727 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005728 { } /* end */
5729};
5730
Takashi Iwaibec15c32008-01-28 18:16:30 +01005731/* update HP, line and mono out pins according to the master switch */
5732static void alc260_hp_master_update(struct hda_codec *codec,
5733 hda_nid_t hp, hda_nid_t line,
5734 hda_nid_t mono)
5735{
5736 struct alc_spec *spec = codec->spec;
5737 unsigned int val = spec->master_sw ? PIN_HP : 0;
5738 /* change HP and line-out pins */
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005739 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005740 val);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005741 snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005742 val);
5743 /* mono (speaker) depending on the HP jack sense */
5744 val = (val && !spec->jack_present) ? PIN_OUT : 0;
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005745 snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005746 val);
5747}
5748
5749static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
5750 struct snd_ctl_elem_value *ucontrol)
5751{
5752 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5753 struct alc_spec *spec = codec->spec;
5754 *ucontrol->value.integer.value = spec->master_sw;
5755 return 0;
5756}
5757
5758static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
5759 struct snd_ctl_elem_value *ucontrol)
5760{
5761 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5762 struct alc_spec *spec = codec->spec;
5763 int val = !!*ucontrol->value.integer.value;
5764 hda_nid_t hp, line, mono;
5765
5766 if (val == spec->master_sw)
5767 return 0;
5768 spec->master_sw = val;
5769 hp = (kcontrol->private_value >> 16) & 0xff;
5770 line = (kcontrol->private_value >> 8) & 0xff;
5771 mono = kcontrol->private_value & 0xff;
5772 alc260_hp_master_update(codec, hp, line, mono);
5773 return 1;
5774}
5775
5776static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
5777 {
5778 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5779 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01005780 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005781 .info = snd_ctl_boolean_mono_info,
5782 .get = alc260_hp_master_sw_get,
5783 .put = alc260_hp_master_sw_put,
5784 .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
5785 },
5786 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5787 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
5788 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5789 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
5790 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
5791 HDA_OUTPUT),
5792 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5793 { } /* end */
5794};
5795
5796static struct hda_verb alc260_hp_unsol_verbs[] = {
5797 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5798 {},
5799};
5800
5801static void alc260_hp_automute(struct hda_codec *codec)
5802{
5803 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01005804
Wu Fengguang864f92b2009-11-18 12:38:02 +08005805 spec->jack_present = snd_hda_jack_detect(codec, 0x10);
Takashi Iwaibec15c32008-01-28 18:16:30 +01005806 alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
5807}
5808
5809static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
5810{
5811 if ((res >> 26) == ALC880_HP_EVENT)
5812 alc260_hp_automute(codec);
5813}
5814
Kailang Yangdf694da2005-12-05 19:42:22 +01005815static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01005816 {
5817 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5818 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01005819 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005820 .info = snd_ctl_boolean_mono_info,
5821 .get = alc260_hp_master_sw_get,
5822 .put = alc260_hp_master_sw_put,
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005823 .private_value = (0x15 << 16) | (0x10 << 8) | 0x11
Takashi Iwaibec15c32008-01-28 18:16:30 +01005824 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005825 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5826 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
5827 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
5828 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
5829 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5830 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01005831 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5832 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02005833 { } /* end */
5834};
5835
Kailang Yang3f878302008-08-26 13:02:23 +02005836static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
5837 .ops = &snd_hda_bind_vol,
5838 .values = {
5839 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
5840 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
5841 HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
5842 0
5843 },
5844};
5845
5846static struct hda_bind_ctls alc260_dc7600_bind_switch = {
5847 .ops = &snd_hda_bind_sw,
5848 .values = {
5849 HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
5850 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
5851 0
5852 },
5853};
5854
5855static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
5856 HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
5857 HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
5858 HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
5859 HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
5860 { } /* end */
5861};
5862
Takashi Iwaibec15c32008-01-28 18:16:30 +01005863static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
5864 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5865 {},
5866};
5867
5868static void alc260_hp_3013_automute(struct hda_codec *codec)
5869{
5870 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01005871
Wu Fengguang864f92b2009-11-18 12:38:02 +08005872 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005873 alc260_hp_master_update(codec, 0x15, 0x10, 0x11);
Takashi Iwaibec15c32008-01-28 18:16:30 +01005874}
5875
5876static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
5877 unsigned int res)
5878{
5879 if ((res >> 26) == ALC880_HP_EVENT)
5880 alc260_hp_3013_automute(codec);
5881}
5882
Kailang Yang3f878302008-08-26 13:02:23 +02005883static void alc260_hp_3012_automute(struct hda_codec *codec)
5884{
Wu Fengguang864f92b2009-11-18 12:38:02 +08005885 unsigned int bits = snd_hda_jack_detect(codec, 0x10) ? 0 : PIN_OUT;
Kailang Yang3f878302008-08-26 13:02:23 +02005886
Kailang Yang3f878302008-08-26 13:02:23 +02005887 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5888 bits);
5889 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5890 bits);
5891 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5892 bits);
5893}
5894
5895static void alc260_hp_3012_unsol_event(struct hda_codec *codec,
5896 unsigned int res)
5897{
5898 if ((res >> 26) == ALC880_HP_EVENT)
5899 alc260_hp_3012_automute(codec);
5900}
5901
5902/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005903 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
5904 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01005905static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005906 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005907 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005908 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005909 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5910 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5911 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
5912 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005913 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01005914 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5915 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01005916 { } /* end */
5917};
5918
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005919/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
5920 * versions of the ALC260 don't act on requests to enable mic bias from NID
5921 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
5922 * datasheet doesn't mention this restriction. At this stage it's not clear
5923 * whether this behaviour is intentional or is a hardware bug in chip
5924 * revisions available in early 2006. Therefore for now allow the
5925 * "Headphone Jack Mode" control to span all choices, but if it turns out
5926 * that the lack of mic bias for this NID is intentional we could change the
5927 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
5928 *
5929 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
5930 * don't appear to make the mic bias available from the "line" jack, even
5931 * though the NID used for this jack (0x14) can supply it. The theory is
5932 * that perhaps Acer have included blocking capacitors between the ALC260
5933 * and the output jack. If this turns out to be the case for all such
5934 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
5935 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01005936 *
5937 * The C20x Tablet series have a mono internal speaker which is controlled
5938 * via the chip's Mono sum widget and pin complex, so include the necessary
5939 * controls for such models. On models without a "mono speaker" the control
5940 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005941 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005942static struct snd_kcontrol_new alc260_acer_mixer[] = {
5943 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5944 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005945 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01005946 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01005947 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01005948 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01005949 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005950 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5951 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5952 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5953 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5954 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5955 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5956 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5957 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005958 { } /* end */
5959};
5960
Michael Schwingencc959482009-02-22 18:58:45 +01005961/* Maxdata Favorit 100XS: one output and one input (0x12) jack
5962 */
5963static struct snd_kcontrol_new alc260_favorit100_mixer[] = {
5964 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5965 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
5966 ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
5967 HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5968 HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5969 ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5970 { } /* end */
5971};
5972
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005973/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
5974 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
5975 */
5976static struct snd_kcontrol_new alc260_will_mixer[] = {
5977 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5978 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
5979 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5980 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5981 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5982 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5983 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5984 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
5985 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5986 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005987 { } /* end */
5988};
5989
5990/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
5991 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
5992 */
5993static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
5994 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5995 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
5996 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5997 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5998 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5999 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
6000 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
6001 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6002 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6003 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
6004 { } /* end */
6005};
6006
Kailang Yangdf694da2005-12-05 19:42:22 +01006007/*
6008 * initialization verbs
6009 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006010static struct hda_verb alc260_init_verbs[] = {
6011 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006012 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006013 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006014 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006015 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006016 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006017 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006018 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006019 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02006020 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006021 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01006022 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006023 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02006024 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006025 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02006026 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006027 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02006028 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6029 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02006030 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006031 /* set connection select to line in (default select for this ADC) */
6032 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02006033 /* mute capture amp left and right */
6034 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6035 /* set connection select to line in (default select for this ADC) */
6036 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02006037 /* set vol=0 Line-Out mixer amp left and right */
6038 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6039 /* unmute pin widget amp left and right (no gain on this amp) */
6040 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6041 /* set vol=0 HP mixer amp left and right */
6042 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6043 /* unmute pin widget amp left and right (no gain on this amp) */
6044 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6045 /* set vol=0 Mono mixer amp left and right */
6046 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6047 /* unmute pin widget amp left and right (no gain on this amp) */
6048 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6049 /* unmute LINE-2 out pin */
6050 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006051 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6052 * Line In 2 = 0x03
6053 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006054 /* mute analog inputs */
6055 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6056 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6057 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6058 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6059 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006060 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02006061 /* mute Front out path */
6062 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6063 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6064 /* mute Headphone out path */
6065 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6066 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6067 /* mute Mono out path */
6068 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6069 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070 { }
6071};
6072
Takashi Iwai474167d2006-05-17 17:17:43 +02006073#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01006074static struct hda_verb alc260_hp_init_verbs[] = {
6075 /* Headphone and output */
6076 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
6077 /* mono output */
6078 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6079 /* Mic1 (rear panel) pin widget for input and vref at 80% */
6080 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6081 /* Mic2 (front panel) pin widget for input and vref at 80% */
6082 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6083 /* Line In pin widget for input */
6084 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6085 /* Line-2 pin widget for output */
6086 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6087 /* CD pin widget for input */
6088 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6089 /* unmute amp left and right */
6090 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
6091 /* set connection select to line in (default select for this ADC) */
6092 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
6093 /* unmute Line-Out mixer amp left and right (volume = 0) */
6094 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6095 /* mute pin widget amp left and right (no gain on this amp) */
6096 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
6097 /* unmute HP mixer amp left and right (volume = 0) */
6098 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6099 /* mute pin widget amp left and right (no gain on this amp) */
6100 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006101 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6102 * Line In 2 = 0x03
6103 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006104 /* mute analog inputs */
6105 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6106 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6107 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6108 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6109 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006110 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
6111 /* Unmute Front out path */
6112 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6113 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6114 /* Unmute Headphone out path */
6115 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6116 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6117 /* Unmute Mono out path */
6118 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6119 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6120 { }
6121};
Takashi Iwai474167d2006-05-17 17:17:43 +02006122#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01006123
6124static struct hda_verb alc260_hp_3013_init_verbs[] = {
6125 /* Line out and output */
6126 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6127 /* mono output */
6128 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6129 /* Mic1 (rear panel) pin widget for input and vref at 80% */
6130 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6131 /* Mic2 (front panel) pin widget for input and vref at 80% */
6132 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6133 /* Line In pin widget for input */
6134 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6135 /* Headphone pin widget for output */
6136 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
6137 /* CD pin widget for input */
6138 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6139 /* unmute amp left and right */
6140 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
6141 /* set connection select to line in (default select for this ADC) */
6142 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
6143 /* unmute Line-Out mixer amp left and right (volume = 0) */
6144 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6145 /* mute pin widget amp left and right (no gain on this amp) */
6146 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
6147 /* unmute HP mixer amp left and right (volume = 0) */
6148 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6149 /* mute pin widget amp left and right (no gain on this amp) */
6150 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006151 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6152 * Line In 2 = 0x03
6153 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006154 /* mute analog inputs */
6155 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6156 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6157 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6158 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6159 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006160 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
6161 /* Unmute Front out path */
6162 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6163 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6164 /* Unmute Headphone out path */
6165 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6166 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6167 /* Unmute Mono out path */
6168 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6169 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6170 { }
6171};
6172
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006173/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006174 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
6175 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006176 */
6177static struct hda_verb alc260_fujitsu_init_verbs[] = {
6178 /* Disable all GPIOs */
6179 {0x01, AC_VERB_SET_GPIO_MASK, 0},
6180 /* Internal speaker is connected to headphone pin */
6181 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6182 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
6183 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006184 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
6185 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6186 /* Ensure all other unused pins are disabled and muted. */
6187 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6188 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006189 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006190 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006191 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006192 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6193 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6194 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006195
Jonathan Woithef7ace402006-02-28 11:46:14 +01006196 /* Disable digital (SPDIF) pins */
6197 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6198 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006199
Kailang Yangea1fb292008-08-26 12:58:38 +02006200 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
Jonathan Woithef7ace402006-02-28 11:46:14 +01006201 * when acting as an output.
6202 */
6203 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6204
6205 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01006206 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6207 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6208 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6209 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6210 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6211 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6212 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6213 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6214 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006215
Jonathan Woithef7ace402006-02-28 11:46:14 +01006216 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
6217 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6218 /* Unmute Line1 pin widget output buffer since it starts as an output.
6219 * If the pin mode is changed by the user the pin mode control will
6220 * take care of enabling the pin's input/output buffers as needed.
6221 * Therefore there's no need to enable the input buffer at this
6222 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006223 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01006224 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +02006225 /* Unmute input buffer of pin widget used for Line-in (no equiv
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006226 * mixer ctrl)
6227 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01006228 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006229
Jonathan Woithef7ace402006-02-28 11:46:14 +01006230 /* Mute capture amp left and right */
6231 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006232 /* Set ADC connection select to match default mixer setting - line
Jonathan Woithef7ace402006-02-28 11:46:14 +01006233 * in (on mic1 pin)
6234 */
6235 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006236
Jonathan Woithef7ace402006-02-28 11:46:14 +01006237 /* Do the same for the second ADC: mute capture input amp and
6238 * set ADC connection to line in (on mic1 pin)
6239 */
6240 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6241 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006242
Jonathan Woithef7ace402006-02-28 11:46:14 +01006243 /* Mute all inputs to mixer widget (even unconnected ones) */
6244 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6245 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6246 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6247 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6248 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6249 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6250 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6251 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01006252
6253 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006254};
6255
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006256/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
6257 * similar laptops (adapted from Fujitsu init verbs).
6258 */
6259static struct hda_verb alc260_acer_init_verbs[] = {
6260 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
6261 * the headphone jack. Turn this on and rely on the standard mute
6262 * methods whenever the user wants to turn these outputs off.
6263 */
6264 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6265 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6266 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
6267 /* Internal speaker/Headphone jack is connected to Line-out pin */
6268 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6269 /* Internal microphone/Mic jack is connected to Mic1 pin */
6270 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
6271 /* Line In jack is connected to Line1 pin */
6272 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01006273 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
6274 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006275 /* Ensure all other unused pins are disabled and muted. */
6276 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6277 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006278 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6279 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6280 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6281 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6282 /* Disable digital (SPDIF) pins */
6283 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6284 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6285
Kailang Yangea1fb292008-08-26 12:58:38 +02006286 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006287 * bus when acting as outputs.
6288 */
6289 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6290 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6291
6292 /* Start with output sum widgets muted and their output gains at min */
6293 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6294 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6295 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6296 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6297 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6298 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6299 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6300 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6301 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6302
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006303 /* Unmute Line-out pin widget amp left and right
6304 * (no equiv mixer ctrl)
6305 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006306 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01006307 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
6308 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006309 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
6310 * inputs. If the pin mode is changed by the user the pin mode control
6311 * will take care of enabling the pin's input/output buffers as needed.
6312 * Therefore there's no need to enable the input buffer at this
6313 * stage.
6314 */
6315 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6316 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6317
6318 /* Mute capture amp left and right */
6319 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6320 /* Set ADC connection select to match default mixer setting - mic
6321 * (on mic1 pin)
6322 */
6323 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6324
6325 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006326 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006327 */
6328 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006329 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006330
6331 /* Mute all inputs to mixer widget (even unconnected ones) */
6332 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6333 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6334 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6335 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6336 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6337 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6338 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6339 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6340
6341 { }
6342};
6343
Michael Schwingencc959482009-02-22 18:58:45 +01006344/* Initialisation sequence for Maxdata Favorit 100XS
6345 * (adapted from Acer init verbs).
6346 */
6347static struct hda_verb alc260_favorit100_init_verbs[] = {
6348 /* GPIO 0 enables the output jack.
6349 * Turn this on and rely on the standard mute
6350 * methods whenever the user wants to turn these outputs off.
6351 */
6352 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6353 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6354 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
6355 /* Line/Mic input jack is connected to Mic1 pin */
6356 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
6357 /* Ensure all other unused pins are disabled and muted. */
6358 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6359 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6360 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6361 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6362 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6363 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6364 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6365 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6366 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6367 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6368 /* Disable digital (SPDIF) pins */
6369 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6370 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6371
6372 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
6373 * bus when acting as outputs.
6374 */
6375 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6376 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6377
6378 /* Start with output sum widgets muted and their output gains at min */
6379 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6380 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6381 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6382 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6383 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6384 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6385 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6386 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6387 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6388
6389 /* Unmute Line-out pin widget amp left and right
6390 * (no equiv mixer ctrl)
6391 */
6392 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6393 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
6394 * inputs. If the pin mode is changed by the user the pin mode control
6395 * will take care of enabling the pin's input/output buffers as needed.
6396 * Therefore there's no need to enable the input buffer at this
6397 * stage.
6398 */
6399 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6400
6401 /* Mute capture amp left and right */
6402 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6403 /* Set ADC connection select to match default mixer setting - mic
6404 * (on mic1 pin)
6405 */
6406 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6407
6408 /* Do similar with the second ADC: mute capture input amp and
6409 * set ADC connection to mic to match ALSA's default state.
6410 */
6411 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6412 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6413
6414 /* Mute all inputs to mixer widget (even unconnected ones) */
6415 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6416 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6417 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6418 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6419 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6420 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6421 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6422 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6423
6424 { }
6425};
6426
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006427static struct hda_verb alc260_will_verbs[] = {
6428 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6429 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
6430 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
6431 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
6432 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
6433 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
6434 {}
6435};
6436
6437static struct hda_verb alc260_replacer_672v_verbs[] = {
6438 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
6439 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
6440 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
6441
6442 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6443 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6444 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6445
6446 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6447 {}
6448};
6449
6450/* toggle speaker-output according to the hp-jack state */
6451static void alc260_replacer_672v_automute(struct hda_codec *codec)
6452{
6453 unsigned int present;
6454
6455 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
Wu Fengguang864f92b2009-11-18 12:38:02 +08006456 present = snd_hda_jack_detect(codec, 0x0f);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006457 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006458 snd_hda_codec_write_cache(codec, 0x01, 0,
6459 AC_VERB_SET_GPIO_DATA, 1);
6460 snd_hda_codec_write_cache(codec, 0x0f, 0,
6461 AC_VERB_SET_PIN_WIDGET_CONTROL,
6462 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006463 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006464 snd_hda_codec_write_cache(codec, 0x01, 0,
6465 AC_VERB_SET_GPIO_DATA, 0);
6466 snd_hda_codec_write_cache(codec, 0x0f, 0,
6467 AC_VERB_SET_PIN_WIDGET_CONTROL,
6468 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006469 }
6470}
6471
6472static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
6473 unsigned int res)
6474{
6475 if ((res >> 26) == ALC880_HP_EVENT)
6476 alc260_replacer_672v_automute(codec);
6477}
6478
Kailang Yang3f878302008-08-26 13:02:23 +02006479static struct hda_verb alc260_hp_dc7600_verbs[] = {
6480 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
6481 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
6482 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6483 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6484 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6485 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6486 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6487 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6488 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6489 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6490 {}
6491};
6492
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006493/* Test configuration for debugging, modelled after the ALC880 test
6494 * configuration.
6495 */
6496#ifdef CONFIG_SND_DEBUG
6497static hda_nid_t alc260_test_dac_nids[1] = {
6498 0x02,
6499};
6500static hda_nid_t alc260_test_adc_nids[2] = {
6501 0x04, 0x05,
6502};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006503/* For testing the ALC260, each input MUX needs its own definition since
Kailang Yangea1fb292008-08-26 12:58:38 +02006504 * the signal assignments are different. This assumes that the first ADC
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006505 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01006506 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006507static struct hda_input_mux alc260_test_capture_sources[2] = {
6508 {
6509 .num_items = 7,
6510 .items = {
6511 { "MIC1 pin", 0x0 },
6512 { "MIC2 pin", 0x1 },
6513 { "LINE1 pin", 0x2 },
6514 { "LINE2 pin", 0x3 },
6515 { "CD pin", 0x4 },
6516 { "LINE-OUT pin", 0x5 },
6517 { "HP-OUT pin", 0x6 },
6518 },
6519 },
6520 {
6521 .num_items = 8,
6522 .items = {
6523 { "MIC1 pin", 0x0 },
6524 { "MIC2 pin", 0x1 },
6525 { "LINE1 pin", 0x2 },
6526 { "LINE2 pin", 0x3 },
6527 { "CD pin", 0x4 },
6528 { "Mixer", 0x5 },
6529 { "LINE-OUT pin", 0x6 },
6530 { "HP-OUT pin", 0x7 },
6531 },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006532 },
6533};
6534static struct snd_kcontrol_new alc260_test_mixer[] = {
6535 /* Output driver widgets */
6536 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
6537 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
6538 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6539 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
6540 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6541 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
6542
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006543 /* Modes for retasking pin widgets
6544 * Note: the ALC260 doesn't seem to act on requests to enable mic
6545 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
6546 * mention this restriction. At this stage it's not clear whether
6547 * this behaviour is intentional or is a hardware bug in chip
6548 * revisions available at least up until early 2006. Therefore for
6549 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
6550 * choices, but if it turns out that the lack of mic bias for these
6551 * NIDs is intentional we could change their modes from
6552 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
6553 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006554 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
6555 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
6556 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
6557 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
6558 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
6559 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
6560
6561 /* Loopback mixer controls */
6562 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
6563 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
6564 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
6565 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
6566 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
6567 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
6568 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
6569 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
6570 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6571 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006572 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
6573 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
6574 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
6575 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01006576
6577 /* Controls for GPIO pins, assuming they are configured as outputs */
6578 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
6579 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
6580 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
6581 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
6582
Jonathan Woithe92621f12006-02-28 11:47:47 +01006583 /* Switches to allow the digital IO pins to be enabled. The datasheet
6584 * is ambigious as to which NID is which; testing on laptops which
Kailang Yangea1fb292008-08-26 12:58:38 +02006585 * make this output available should provide clarification.
Jonathan Woithe92621f12006-02-28 11:47:47 +01006586 */
6587 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
6588 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
6589
Jonathan Woithef8225f62008-01-08 12:16:54 +01006590 /* A switch allowing EAPD to be enabled. Some laptops seem to use
6591 * this output to turn on an external amplifier.
6592 */
6593 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
6594 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
6595
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006596 { } /* end */
6597};
6598static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01006599 /* Enable all GPIOs as outputs with an initial value of 0 */
6600 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
6601 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6602 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
6603
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006604 /* Enable retasking pins as output, initially without power amp */
6605 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6606 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6607 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6608 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6609 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6610 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6611
Jonathan Woithe92621f12006-02-28 11:47:47 +01006612 /* Disable digital (SPDIF) pins initially, but users can enable
6613 * them via a mixer switch. In the case of SPDIF-out, this initverb
6614 * payload also sets the generation to 0, output to be in "consumer"
6615 * PCM format, copyright asserted, no pre-emphasis and no validity
6616 * control.
6617 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006618 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6619 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6620
Kailang Yangea1fb292008-08-26 12:58:38 +02006621 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006622 * OUT1 sum bus when acting as an output.
6623 */
6624 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6625 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
6626 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6627 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
6628
6629 /* Start with output sum widgets muted and their output gains at min */
6630 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6631 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6632 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6633 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6634 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6635 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6636 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6637 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6638 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6639
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006640 /* Unmute retasking pin widget output buffers since the default
6641 * state appears to be output. As the pin mode is changed by the
6642 * user the pin mode control will take care of enabling the pin's
6643 * input/output buffers as needed.
6644 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006645 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6646 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6647 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6648 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6649 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6650 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6651 /* Also unmute the mono-out pin widget */
6652 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6653
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006654 /* Mute capture amp left and right */
6655 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006656 /* Set ADC connection select to match default mixer setting (mic1
6657 * pin)
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006658 */
6659 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6660
6661 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01006662 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006663 */
6664 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6665 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6666
6667 /* Mute all inputs to mixer widget (even unconnected ones) */
6668 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6669 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6670 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6671 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6672 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6673 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6674 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6675 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6676
6677 { }
6678};
6679#endif
6680
Takashi Iwai63300792008-01-24 15:31:36 +01006681#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
6682#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07006683
Takashi Iwaia3bcba32005-12-06 19:05:29 +01006684#define alc260_pcm_digital_playback alc880_pcm_digital_playback
6685#define alc260_pcm_digital_capture alc880_pcm_digital_capture
6686
Kailang Yangdf694da2005-12-05 19:42:22 +01006687/*
6688 * for BIOS auto-configuration
6689 */
6690
6691static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai863b4512008-10-21 17:01:47 +02006692 const char *pfx, int *vol_bits)
Kailang Yangdf694da2005-12-05 19:42:22 +01006693{
6694 hda_nid_t nid_vol;
6695 unsigned long vol_val, sw_val;
Kailang Yangdf694da2005-12-05 19:42:22 +01006696 int err;
6697
6698 if (nid >= 0x0f && nid < 0x11) {
6699 nid_vol = nid - 0x7;
6700 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
6701 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
6702 } else if (nid == 0x11) {
6703 nid_vol = nid - 0x7;
6704 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
6705 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
6706 } else if (nid >= 0x12 && nid <= 0x15) {
6707 nid_vol = 0x08;
6708 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
6709 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
6710 } else
6711 return 0; /* N/A */
Kailang Yangea1fb292008-08-26 12:58:38 +02006712
Takashi Iwai863b4512008-10-21 17:01:47 +02006713 if (!(*vol_bits & (1 << nid_vol))) {
6714 /* first control for the volume widget */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02006715 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, vol_val);
Takashi Iwai863b4512008-10-21 17:01:47 +02006716 if (err < 0)
6717 return err;
6718 *vol_bits |= (1 << nid_vol);
6719 }
Takashi Iwai0afe5f82009-10-02 09:20:00 +02006720 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, sw_val);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006721 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006722 return err;
6723 return 1;
6724}
6725
6726/* add playback controls from the parsed DAC table */
6727static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
6728 const struct auto_pin_cfg *cfg)
6729{
6730 hda_nid_t nid;
6731 int err;
Takashi Iwai863b4512008-10-21 17:01:47 +02006732 int vols = 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01006733
6734 spec->multiout.num_dacs = 1;
6735 spec->multiout.dac_nids = spec->private_dac_nids;
6736 spec->multiout.dac_nids[0] = 0x02;
6737
6738 nid = cfg->line_out_pins[0];
6739 if (nid) {
Takashi Iwai23112d62009-08-25 16:07:08 +02006740 const char *pfx;
6741 if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
6742 pfx = "Master";
6743 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
6744 pfx = "Speaker";
6745 else
6746 pfx = "Front";
6747 err = alc260_add_playback_controls(spec, nid, pfx, &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006748 if (err < 0)
6749 return err;
6750 }
6751
Takashi Iwai82bc9552006-03-21 11:24:42 +01006752 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006753 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02006754 err = alc260_add_playback_controls(spec, nid, "Speaker", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006755 if (err < 0)
6756 return err;
6757 }
6758
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006759 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006760 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02006761 err = alc260_add_playback_controls(spec, nid, "Headphone",
6762 &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006763 if (err < 0)
6764 return err;
6765 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006766 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01006767}
6768
6769/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +02006770static int alc260_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yangdf694da2005-12-05 19:42:22 +01006771 const struct auto_pin_cfg *cfg)
6772{
Takashi Iwai05f5f472009-08-25 13:10:18 +02006773 return alc_auto_create_input_ctls(codec, cfg, 0x07, 0x04, 0x05);
Kailang Yangdf694da2005-12-05 19:42:22 +01006774}
6775
6776static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
6777 hda_nid_t nid, int pin_type,
6778 int sel_idx)
6779{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006780 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006781 /* need the manual connection? */
6782 if (nid >= 0x12) {
6783 int idx = nid - 0x12;
6784 snd_hda_codec_write(codec, idx + 0x0b, 0,
6785 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01006786 }
6787}
6788
6789static void alc260_auto_init_multi_out(struct hda_codec *codec)
6790{
6791 struct alc_spec *spec = codec->spec;
6792 hda_nid_t nid;
6793
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006794 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006795 if (nid) {
6796 int pin_type = get_pin_type(spec->autocfg.line_out_type);
6797 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
6798 }
Kailang Yangea1fb292008-08-26 12:58:38 +02006799
Takashi Iwai82bc9552006-03-21 11:24:42 +01006800 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006801 if (nid)
6802 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
6803
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006804 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006805 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006806 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006807}
Kailang Yangdf694da2005-12-05 19:42:22 +01006808
6809#define ALC260_PIN_CD_NID 0x16
6810static void alc260_auto_init_analog_input(struct hda_codec *codec)
6811{
6812 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02006813 struct auto_pin_cfg *cfg = &spec->autocfg;
Kailang Yangdf694da2005-12-05 19:42:22 +01006814 int i;
6815
Takashi Iwai66ceeb62010-08-30 13:05:52 +02006816 for (i = 0; i < cfg->num_inputs; i++) {
6817 hda_nid_t nid = cfg->inputs[i].pin;
Kailang Yangdf694da2005-12-05 19:42:22 +01006818 if (nid >= 0x12) {
Takashi Iwai30ea0982010-09-16 18:47:56 +02006819 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwaie82c0252009-03-23 15:17:38 +01006820 if (nid != ALC260_PIN_CD_NID &&
6821 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006822 snd_hda_codec_write(codec, nid, 0,
6823 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01006824 AMP_OUT_MUTE);
6825 }
6826 }
6827}
6828
Takashi Iwai7f311a42010-04-09 17:32:23 +02006829#define alc260_auto_init_input_src alc880_auto_init_input_src
6830
Kailang Yangdf694da2005-12-05 19:42:22 +01006831/*
6832 * generic initialization of ADC, input mixers and output mixers
6833 */
6834static struct hda_verb alc260_volume_init_verbs[] = {
6835 /*
6836 * Unmute ADC0-1 and set the default input to mic-in
6837 */
6838 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6839 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6840 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6841 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006842
Kailang Yangdf694da2005-12-05 19:42:22 +01006843 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
6844 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006845 * Note: PASD motherboards uses the Line In 2 as the input for
6846 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01006847 */
6848 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006849 /* mute analog inputs */
6850 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6851 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6852 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6853 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6854 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006855
6856 /*
6857 * Set up output mixers (0x08 - 0x0a)
6858 */
6859 /* set vol=0 to output mixers */
6860 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6861 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6862 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6863 /* set up input amps for analog loopback */
6864 /* Amp Indices: DAC = 0, mixer = 1 */
6865 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6866 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6867 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6868 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6869 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6870 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006871
Kailang Yangdf694da2005-12-05 19:42:22 +01006872 { }
6873};
6874
6875static int alc260_parse_auto_config(struct hda_codec *codec)
6876{
6877 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006878 int err;
6879 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
6880
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006881 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
6882 alc260_ignore);
6883 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006884 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006885 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
6886 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01006887 return err;
Takashi Iwai603c4012008-07-30 15:01:44 +02006888 if (!spec->kctls.list)
Kailang Yangdf694da2005-12-05 19:42:22 +01006889 return 0; /* can't find valid BIOS pin config */
Takashi Iwai05f5f472009-08-25 13:10:18 +02006890 err = alc260_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006891 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006892 return err;
6893
6894 spec->multiout.max_channels = 2;
6895
Takashi Iwai0852d7a2009-02-11 11:35:15 +01006896 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +01006897 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
Takashi Iwai603c4012008-07-30 15:01:44 +02006898 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01006899 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +01006900
Takashi Iwaid88897e2008-10-31 15:01:37 +01006901 add_verb(spec, alc260_volume_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +01006902
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006903 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02006904 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006905
Kailang Yang6227cdc2010-02-25 08:36:52 +01006906 alc_ssid_check(codec, 0x10, 0x15, 0x0f, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02006907
Kailang Yangdf694da2005-12-05 19:42:22 +01006908 return 1;
6909}
6910
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006911/* additional initialization for auto-configuration model */
6912static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01006913{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006914 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006915 alc260_auto_init_multi_out(codec);
6916 alc260_auto_init_analog_input(codec);
Takashi Iwai7f311a42010-04-09 17:32:23 +02006917 alc260_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +02006918 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006919 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02006920 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01006921}
6922
Takashi Iwaicb53c622007-08-10 17:21:45 +02006923#ifdef CONFIG_SND_HDA_POWER_SAVE
6924static struct hda_amp_list alc260_loopbacks[] = {
6925 { 0x07, HDA_INPUT, 0 },
6926 { 0x07, HDA_INPUT, 1 },
6927 { 0x07, HDA_INPUT, 2 },
6928 { 0x07, HDA_INPUT, 3 },
6929 { 0x07, HDA_INPUT, 4 },
6930 { } /* end */
6931};
6932#endif
6933
Kailang Yangdf694da2005-12-05 19:42:22 +01006934/*
Takashi Iwaifc091762010-08-04 23:53:36 +02006935 * Pin config fixes
6936 */
6937enum {
6938 PINFIX_HP_DC5750,
6939};
6940
Takashi Iwaifc091762010-08-04 23:53:36 +02006941static const struct alc_fixup alc260_fixups[] = {
6942 [PINFIX_HP_DC5750] = {
Takashi Iwai73413b12010-08-30 09:39:57 +02006943 .pins = (const struct alc_pincfg[]) {
6944 { 0x11, 0x90130110 }, /* speaker */
6945 { }
6946 }
Takashi Iwaifc091762010-08-04 23:53:36 +02006947 },
6948};
6949
6950static struct snd_pci_quirk alc260_fixup_tbl[] = {
6951 SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750),
6952 {}
6953};
6954
6955/*
Kailang Yangdf694da2005-12-05 19:42:22 +01006956 * ALC260 configurations
6957 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006958static const char *alc260_models[ALC260_MODEL_LAST] = {
6959 [ALC260_BASIC] = "basic",
6960 [ALC260_HP] = "hp",
6961 [ALC260_HP_3013] = "hp-3013",
Takashi Iwai2922c9a2008-08-27 18:12:42 +02006962 [ALC260_HP_DC7600] = "hp-dc7600",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006963 [ALC260_FUJITSU_S702X] = "fujitsu",
6964 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006965 [ALC260_WILL] = "will",
6966 [ALC260_REPLACER_672V] = "replacer",
Michael Schwingencc959482009-02-22 18:58:45 +01006967 [ALC260_FAVORIT100] = "favorit100",
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006968#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006969 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006970#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006971 [ALC260_AUTO] = "auto",
6972};
6973
6974static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01006975 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Daniel T Chen950200e2009-12-13 14:11:02 -05006976 SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006977 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Michael Schwingencc959482009-02-22 18:58:45 +01006978 SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100),
Takashi Iwai9720b712007-03-13 21:46:23 +01006979 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwai4ac55982009-11-10 16:08:45 +01006980 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006981 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
Jaroslav Kysela34ec8a02008-07-10 14:49:19 +02006982 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
Kailang Yang3f878302008-08-26 13:02:23 +02006983 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006984 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
6985 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
6986 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
6987 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
6988 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
6989 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
6990 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
6991 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
6992 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006993 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006994 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02006995 {}
6996};
6997
Kailang Yangdf694da2005-12-05 19:42:22 +01006998static struct alc_config_preset alc260_presets[] = {
6999 [ALC260_BASIC] = {
7000 .mixers = { alc260_base_output_mixer,
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007001 alc260_input_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01007002 .init_verbs = { alc260_init_verbs },
7003 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7004 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007005 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
Takashi Iwai9c4cc0b2010-03-15 09:07:52 +01007006 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01007007 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7008 .channel_mode = alc260_modes,
7009 .input_mux = &alc260_capture_source,
7010 },
7011 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01007012 .mixers = { alc260_hp_output_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007013 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01007014 .init_verbs = { alc260_init_verbs,
7015 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01007016 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7017 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007018 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7019 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01007020 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7021 .channel_mode = alc260_modes,
7022 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01007023 .unsol_event = alc260_hp_unsol_event,
7024 .init_hook = alc260_hp_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01007025 },
Kailang Yang3f878302008-08-26 13:02:23 +02007026 [ALC260_HP_DC7600] = {
7027 .mixers = { alc260_hp_dc7600_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007028 alc260_input_mixer },
Kailang Yang3f878302008-08-26 13:02:23 +02007029 .init_verbs = { alc260_init_verbs,
7030 alc260_hp_dc7600_verbs },
7031 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7032 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007033 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7034 .adc_nids = alc260_adc_nids_alt,
Kailang Yang3f878302008-08-26 13:02:23 +02007035 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7036 .channel_mode = alc260_modes,
7037 .input_mux = &alc260_capture_source,
7038 .unsol_event = alc260_hp_3012_unsol_event,
7039 .init_hook = alc260_hp_3012_automute,
7040 },
Kailang Yangdf694da2005-12-05 19:42:22 +01007041 [ALC260_HP_3013] = {
7042 .mixers = { alc260_hp_3013_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007043 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01007044 .init_verbs = { alc260_hp_3013_init_verbs,
7045 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01007046 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7047 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007048 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7049 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01007050 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7051 .channel_mode = alc260_modes,
7052 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01007053 .unsol_event = alc260_hp_3013_unsol_event,
7054 .init_hook = alc260_hp_3013_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01007055 },
7056 [ALC260_FUJITSU_S702X] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007057 .mixers = { alc260_fujitsu_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01007058 .init_verbs = { alc260_fujitsu_init_verbs },
7059 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7060 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01007061 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7062 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01007063 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7064 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007065 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
7066 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01007067 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007068 [ALC260_ACER] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007069 .mixers = { alc260_acer_mixer },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007070 .init_verbs = { alc260_acer_init_verbs },
7071 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7072 .dac_nids = alc260_dac_nids,
7073 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7074 .adc_nids = alc260_dual_adc_nids,
7075 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7076 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007077 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
7078 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007079 },
Michael Schwingencc959482009-02-22 18:58:45 +01007080 [ALC260_FAVORIT100] = {
7081 .mixers = { alc260_favorit100_mixer },
7082 .init_verbs = { alc260_favorit100_init_verbs },
7083 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7084 .dac_nids = alc260_dac_nids,
7085 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7086 .adc_nids = alc260_dual_adc_nids,
7087 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7088 .channel_mode = alc260_modes,
7089 .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources),
7090 .input_mux = alc260_favorit100_capture_sources,
7091 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007092 [ALC260_WILL] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007093 .mixers = { alc260_will_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007094 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
7095 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7096 .dac_nids = alc260_dac_nids,
7097 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
7098 .adc_nids = alc260_adc_nids,
7099 .dig_out_nid = ALC260_DIGOUT_NID,
7100 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7101 .channel_mode = alc260_modes,
7102 .input_mux = &alc260_capture_source,
7103 },
7104 [ALC260_REPLACER_672V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007105 .mixers = { alc260_replacer_672v_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007106 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
7107 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7108 .dac_nids = alc260_dac_nids,
7109 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
7110 .adc_nids = alc260_adc_nids,
7111 .dig_out_nid = ALC260_DIGOUT_NID,
7112 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7113 .channel_mode = alc260_modes,
7114 .input_mux = &alc260_capture_source,
7115 .unsol_event = alc260_replacer_672v_unsol_event,
7116 .init_hook = alc260_replacer_672v_automute,
7117 },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01007118#ifdef CONFIG_SND_DEBUG
7119 [ALC260_TEST] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007120 .mixers = { alc260_test_mixer },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01007121 .init_verbs = { alc260_test_init_verbs },
7122 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
7123 .dac_nids = alc260_test_dac_nids,
7124 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
7125 .adc_nids = alc260_test_adc_nids,
7126 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7127 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007128 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
7129 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01007130 },
7131#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01007132};
7133
Linus Torvalds1da177e2005-04-16 15:20:36 -07007134static int patch_alc260(struct hda_codec *codec)
7135{
7136 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007137 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007138
Takashi Iwaie560d8d2005-09-09 14:21:46 +02007139 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007140 if (spec == NULL)
7141 return -ENOMEM;
7142
7143 codec->spec = spec;
7144
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007145 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
7146 alc260_models,
7147 alc260_cfg_tbl);
7148 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02007149 snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai6c627f32009-05-18 12:33:36 +02007150 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +01007151 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02007152 }
7153
Takashi Iwaifc091762010-08-04 23:53:36 +02007154 if (board_config == ALC260_AUTO)
7155 alc_pick_fixup(codec, alc260_fixup_tbl, alc260_fixups, 1);
7156
Kailang Yangdf694da2005-12-05 19:42:22 +01007157 if (board_config == ALC260_AUTO) {
7158 /* automatic parse from the BIOS config */
7159 err = alc260_parse_auto_config(codec);
7160 if (err < 0) {
7161 alc_free(codec);
7162 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007163 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007164 printk(KERN_INFO
7165 "hda_codec: Cannot set up configuration "
7166 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01007167 board_config = ALC260_BASIC;
7168 }
Takashi Iwai16ded522005-06-10 19:58:24 +02007169 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007170
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09007171 err = snd_hda_attach_beep_device(codec, 0x1);
7172 if (err < 0) {
7173 alc_free(codec);
7174 return err;
7175 }
7176
Kailang Yangdf694da2005-12-05 19:42:22 +01007177 if (board_config != ALC260_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02007178 setup_preset(codec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007179
Linus Torvalds1da177e2005-04-16 15:20:36 -07007180 spec->stream_analog_playback = &alc260_pcm_analog_playback;
7181 spec->stream_analog_capture = &alc260_pcm_analog_capture;
Jonathan Woithe53bacfb2010-08-08 00:17:05 +09307182 spec->stream_analog_alt_capture = &alc260_pcm_analog_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007183
Takashi Iwaia3bcba32005-12-06 19:05:29 +01007184 spec->stream_digital_playback = &alc260_pcm_digital_playback;
7185 spec->stream_digital_capture = &alc260_pcm_digital_capture;
7186
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01007187 if (!spec->adc_nids && spec->input_mux) {
7188 /* check whether NID 0x04 is valid */
7189 unsigned int wcap = get_wcaps(codec, 0x04);
Takashi Iwaia22d5432009-07-27 12:54:26 +02007190 wcap = get_wcaps_type(wcap);
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01007191 /* get type */
7192 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
7193 spec->adc_nids = alc260_adc_nids_alt;
7194 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
7195 } else {
7196 spec->adc_nids = alc260_adc_nids;
7197 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
7198 }
7199 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02007200 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007201 set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007202
Takashi Iwaifc091762010-08-04 23:53:36 +02007203 if (board_config == ALC260_AUTO)
7204 alc_pick_fixup(codec, alc260_fixup_tbl, alc260_fixups, 0);
7205
Takashi Iwai2134ea42008-01-10 16:53:55 +01007206 spec->vmaster_nid = 0x08;
7207
Linus Torvalds1da177e2005-04-16 15:20:36 -07007208 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01007209 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007210 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02007211#ifdef CONFIG_SND_HDA_POWER_SAVE
7212 if (!spec->loopback.amplist)
7213 spec->loopback.amplist = alc260_loopbacks;
7214#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007215
7216 return 0;
7217}
7218
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007219
Linus Torvalds1da177e2005-04-16 15:20:36 -07007220/*
Takashi Iwai4953550a2009-06-30 15:28:30 +02007221 * ALC882/883/885/888/889 support
Linus Torvalds1da177e2005-04-16 15:20:36 -07007222 *
7223 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
7224 * configuration. Each pin widget can choose any input DACs and a mixer.
7225 * Each ADC is connected from a mixer of all inputs. This makes possible
7226 * 6-channel independent captures.
7227 *
7228 * In addition, an independent DAC for the multi-playback (not used in this
7229 * driver yet).
7230 */
Kailang Yangdf694da2005-12-05 19:42:22 +01007231#define ALC882_DIGOUT_NID 0x06
7232#define ALC882_DIGIN_NID 0x0a
Takashi Iwai4953550a2009-06-30 15:28:30 +02007233#define ALC883_DIGOUT_NID ALC882_DIGOUT_NID
7234#define ALC883_DIGIN_NID ALC882_DIGIN_NID
7235#define ALC1200_DIGOUT_NID 0x10
7236
Linus Torvalds1da177e2005-04-16 15:20:36 -07007237
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01007238static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007239 { 8, NULL }
7240};
7241
Takashi Iwai4953550a2009-06-30 15:28:30 +02007242/* DACs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007243static hda_nid_t alc882_dac_nids[4] = {
7244 /* front, rear, clfe, rear_surr */
7245 0x02, 0x03, 0x04, 0x05
7246};
Takashi Iwai4953550a2009-06-30 15:28:30 +02007247#define alc883_dac_nids alc882_dac_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007248
Takashi Iwai4953550a2009-06-30 15:28:30 +02007249/* ADCs */
Kailang Yangdf694da2005-12-05 19:42:22 +01007250#define alc882_adc_nids alc880_adc_nids
7251#define alc882_adc_nids_alt alc880_adc_nids_alt
Takashi Iwai4953550a2009-06-30 15:28:30 +02007252#define alc883_adc_nids alc882_adc_nids_alt
7253static hda_nid_t alc883_adc_nids_alt[1] = { 0x08 };
7254static hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 };
7255#define alc889_adc_nids alc880_adc_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007256
Takashi Iwaie1406342008-02-11 18:32:32 +01007257static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
7258static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
Takashi Iwai4953550a2009-06-30 15:28:30 +02007259#define alc883_capsrc_nids alc882_capsrc_nids_alt
7260static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
7261#define alc889_capsrc_nids alc882_capsrc_nids
Takashi Iwaie1406342008-02-11 18:32:32 +01007262
Linus Torvalds1da177e2005-04-16 15:20:36 -07007263/* input MUX */
7264/* FIXME: should be a matrix-type input source selection */
7265
7266static struct hda_input_mux alc882_capture_source = {
7267 .num_items = 4,
7268 .items = {
7269 { "Mic", 0x0 },
7270 { "Front Mic", 0x1 },
7271 { "Line", 0x2 },
7272 { "CD", 0x4 },
7273 },
7274};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007275
Takashi Iwai4953550a2009-06-30 15:28:30 +02007276#define alc883_capture_source alc882_capture_source
7277
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007278static struct hda_input_mux alc889_capture_source = {
7279 .num_items = 3,
7280 .items = {
7281 { "Front Mic", 0x0 },
7282 { "Mic", 0x3 },
7283 { "Line", 0x2 },
7284 },
7285};
7286
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007287static struct hda_input_mux mb5_capture_source = {
7288 .num_items = 3,
7289 .items = {
7290 { "Mic", 0x1 },
Alex Murrayb8f171e2010-06-14 12:08:43 +09307291 { "Line", 0x7 },
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007292 { "CD", 0x4 },
7293 },
7294};
7295
Luke Yelaviche458b1f2010-02-12 16:28:29 +11007296static struct hda_input_mux macmini3_capture_source = {
7297 .num_items = 2,
7298 .items = {
7299 { "Line", 0x2 },
7300 { "CD", 0x4 },
7301 },
7302};
7303
Takashi Iwai4953550a2009-06-30 15:28:30 +02007304static struct hda_input_mux alc883_3stack_6ch_intel = {
7305 .num_items = 4,
7306 .items = {
7307 { "Mic", 0x1 },
7308 { "Front Mic", 0x0 },
7309 { "Line", 0x2 },
7310 { "CD", 0x4 },
7311 },
7312};
7313
7314static struct hda_input_mux alc883_lenovo_101e_capture_source = {
7315 .num_items = 2,
7316 .items = {
7317 { "Mic", 0x1 },
7318 { "Line", 0x2 },
7319 },
7320};
7321
7322static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
7323 .num_items = 4,
7324 .items = {
7325 { "Mic", 0x0 },
David Henningsson150b4322010-07-29 14:46:42 +02007326 { "Int Mic", 0x1 },
Takashi Iwai4953550a2009-06-30 15:28:30 +02007327 { "Line", 0x2 },
7328 { "CD", 0x4 },
7329 },
7330};
7331
7332static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
7333 .num_items = 2,
7334 .items = {
7335 { "Mic", 0x0 },
7336 { "Int Mic", 0x1 },
7337 },
7338};
7339
7340static struct hda_input_mux alc883_lenovo_sky_capture_source = {
7341 .num_items = 3,
7342 .items = {
7343 { "Mic", 0x0 },
7344 { "Front Mic", 0x1 },
7345 { "Line", 0x4 },
7346 },
7347};
7348
7349static struct hda_input_mux alc883_asus_eee1601_capture_source = {
7350 .num_items = 2,
7351 .items = {
7352 { "Mic", 0x0 },
7353 { "Line", 0x2 },
7354 },
7355};
7356
7357static struct hda_input_mux alc889A_mb31_capture_source = {
7358 .num_items = 2,
7359 .items = {
7360 { "Mic", 0x0 },
7361 /* Front Mic (0x01) unused */
7362 { "Line", 0x2 },
7363 /* Line 2 (0x03) unused */
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02007364 /* CD (0x04) unused? */
Takashi Iwai4953550a2009-06-30 15:28:30 +02007365 },
7366};
7367
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07007368static struct hda_input_mux alc889A_imac91_capture_source = {
7369 .num_items = 2,
7370 .items = {
7371 { "Mic", 0x01 },
7372 { "Line", 0x2 }, /* Not sure! */
7373 },
7374};
7375
Takashi Iwai4953550a2009-06-30 15:28:30 +02007376/*
7377 * 2ch mode
7378 */
7379static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
7380 { 2, NULL }
7381};
7382
Kailang Yangdf694da2005-12-05 19:42:22 +01007383/*
Kailang Yang272a5272007-05-14 11:00:38 +02007384 * 2ch mode
7385 */
7386static struct hda_verb alc882_3ST_ch2_init[] = {
7387 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7388 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7389 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7390 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7391 { } /* end */
7392};
7393
7394/*
Takashi Iwai4953550a2009-06-30 15:28:30 +02007395 * 4ch mode
7396 */
7397static struct hda_verb alc882_3ST_ch4_init[] = {
7398 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7399 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7400 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7401 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7402 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7403 { } /* end */
7404};
7405
7406/*
Kailang Yang272a5272007-05-14 11:00:38 +02007407 * 6ch mode
7408 */
7409static struct hda_verb alc882_3ST_ch6_init[] = {
7410 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7411 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7412 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7413 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7414 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7415 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7416 { } /* end */
7417};
7418
Takashi Iwai4953550a2009-06-30 15:28:30 +02007419static struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
Kailang Yang272a5272007-05-14 11:00:38 +02007420 { 2, alc882_3ST_ch2_init },
Takashi Iwai4953550a2009-06-30 15:28:30 +02007421 { 4, alc882_3ST_ch4_init },
Kailang Yang272a5272007-05-14 11:00:38 +02007422 { 6, alc882_3ST_ch6_init },
7423};
7424
Takashi Iwai4953550a2009-06-30 15:28:30 +02007425#define alc883_3ST_6ch_modes alc882_3ST_6ch_modes
7426
Kailang Yang272a5272007-05-14 11:00:38 +02007427/*
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307428 * 2ch mode
7429 */
7430static struct hda_verb alc883_3ST_ch2_clevo_init[] = {
7431 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
7432 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7433 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7434 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7435 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7436 { } /* end */
7437};
7438
7439/*
7440 * 4ch mode
7441 */
7442static struct hda_verb alc883_3ST_ch4_clevo_init[] = {
7443 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7444 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7445 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7446 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7447 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7448 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7449 { } /* end */
7450};
7451
7452/*
7453 * 6ch mode
7454 */
7455static struct hda_verb alc883_3ST_ch6_clevo_init[] = {
7456 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7457 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7458 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7459 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7460 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7461 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7462 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7463 { } /* end */
7464};
7465
7466static struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
7467 { 2, alc883_3ST_ch2_clevo_init },
7468 { 4, alc883_3ST_ch4_clevo_init },
7469 { 6, alc883_3ST_ch6_clevo_init },
7470};
7471
7472
7473/*
Kailang Yangdf694da2005-12-05 19:42:22 +01007474 * 6ch mode
7475 */
7476static struct hda_verb alc882_sixstack_ch6_init[] = {
7477 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7478 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7479 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7480 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7481 { } /* end */
7482};
7483
7484/*
7485 * 8ch mode
7486 */
7487static struct hda_verb alc882_sixstack_ch8_init[] = {
7488 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7489 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7490 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7491 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7492 { } /* end */
7493};
7494
7495static struct hda_channel_mode alc882_sixstack_modes[2] = {
7496 { 6, alc882_sixstack_ch6_init },
7497 { 8, alc882_sixstack_ch8_init },
7498};
7499
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08007500
7501/* Macbook Air 2,1 */
7502
7503static struct hda_channel_mode alc885_mba21_ch_modes[1] = {
7504 { 2, NULL },
7505};
7506
Takashi Iwai87350ad2007-08-16 18:19:38 +02007507/*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04007508 * macbook pro ALC885 can switch LineIn to LineOut without losing Mic
Takashi Iwai87350ad2007-08-16 18:19:38 +02007509 */
7510
7511/*
7512 * 2ch mode
7513 */
7514static struct hda_verb alc885_mbp_ch2_init[] = {
7515 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7516 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7517 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7518 { } /* end */
7519};
7520
7521/*
Takashi Iwaia3f730af2009-08-31 08:15:26 +02007522 * 4ch mode
Takashi Iwai87350ad2007-08-16 18:19:38 +02007523 */
Takashi Iwaia3f730af2009-08-31 08:15:26 +02007524static struct hda_verb alc885_mbp_ch4_init[] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007525 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7526 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7527 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7528 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7529 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7530 { } /* end */
7531};
7532
Takashi Iwaia3f730af2009-08-31 08:15:26 +02007533static struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007534 { 2, alc885_mbp_ch2_init },
Takashi Iwaia3f730af2009-08-31 08:15:26 +02007535 { 4, alc885_mbp_ch4_init },
Takashi Iwai87350ad2007-08-16 18:19:38 +02007536};
7537
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007538/*
7539 * 2ch
7540 * Speakers/Woofer/HP = Front
7541 * LineIn = Input
7542 */
7543static struct hda_verb alc885_mb5_ch2_init[] = {
7544 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7545 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7546 { } /* end */
7547};
7548
7549/*
7550 * 6ch mode
7551 * Speakers/HP = Front
7552 * Woofer = LFE
7553 * LineIn = Surround
7554 */
7555static struct hda_verb alc885_mb5_ch6_init[] = {
7556 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7557 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7558 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7559 { } /* end */
7560};
7561
7562static struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
7563 { 2, alc885_mb5_ch2_init },
7564 { 6, alc885_mb5_ch6_init },
7565};
Takashi Iwai87350ad2007-08-16 18:19:38 +02007566
Takashi Iwaid01aecd2010-02-23 08:07:15 +01007567#define alc885_macmini3_6ch_modes alc885_mb5_6ch_modes
Takashi Iwai4953550a2009-06-30 15:28:30 +02007568
7569/*
7570 * 2ch mode
7571 */
7572static struct hda_verb alc883_4ST_ch2_init[] = {
7573 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7574 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7575 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7576 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7577 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7578 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7579 { } /* end */
7580};
7581
7582/*
7583 * 4ch mode
7584 */
7585static struct hda_verb alc883_4ST_ch4_init[] = {
7586 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7587 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7588 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7589 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
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
7596/*
7597 * 6ch mode
7598 */
7599static struct hda_verb alc883_4ST_ch6_init[] = {
7600 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7601 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7602 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7603 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7604 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7605 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7606 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7607 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7608 { } /* end */
7609};
7610
7611/*
7612 * 8ch mode
7613 */
7614static struct hda_verb alc883_4ST_ch8_init[] = {
7615 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7616 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7617 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7618 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7619 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7620 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7621 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7622 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7623 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7624 { } /* end */
7625};
7626
7627static struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
7628 { 2, alc883_4ST_ch2_init },
7629 { 4, alc883_4ST_ch4_init },
7630 { 6, alc883_4ST_ch6_init },
7631 { 8, alc883_4ST_ch8_init },
7632};
7633
7634
7635/*
7636 * 2ch mode
7637 */
7638static struct hda_verb alc883_3ST_ch2_intel_init[] = {
7639 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7640 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7641 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7642 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7643 { } /* end */
7644};
7645
7646/*
7647 * 4ch mode
7648 */
7649static struct hda_verb alc883_3ST_ch4_intel_init[] = {
7650 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7651 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7652 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7653 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7654 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7655 { } /* end */
7656};
7657
7658/*
7659 * 6ch mode
7660 */
7661static struct hda_verb alc883_3ST_ch6_intel_init[] = {
7662 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7663 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7664 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
7665 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7666 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7667 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7668 { } /* end */
7669};
7670
7671static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
7672 { 2, alc883_3ST_ch2_intel_init },
7673 { 4, alc883_3ST_ch4_intel_init },
7674 { 6, alc883_3ST_ch6_intel_init },
7675};
7676
7677/*
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007678 * 2ch mode
7679 */
7680static struct hda_verb alc889_ch2_intel_init[] = {
7681 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7682 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 },
7683 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 },
7684 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00 },
7685 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7686 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7687 { } /* end */
7688};
7689
7690/*
Takashi Iwai4953550a2009-06-30 15:28:30 +02007691 * 6ch mode
7692 */
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007693static struct hda_verb alc889_ch6_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007694 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7695 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7696 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7697 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7698 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007699 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7700 { } /* end */
7701};
7702
7703/*
7704 * 8ch mode
7705 */
7706static struct hda_verb alc889_ch8_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007707 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7708 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7709 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7710 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7711 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x03 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007712 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7713 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007714 { } /* end */
7715};
7716
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007717static struct hda_channel_mode alc889_8ch_intel_modes[3] = {
7718 { 2, alc889_ch2_intel_init },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007719 { 6, alc889_ch6_intel_init },
7720 { 8, alc889_ch8_intel_init },
7721};
7722
7723/*
7724 * 6ch mode
7725 */
Takashi Iwai4953550a2009-06-30 15:28:30 +02007726static struct hda_verb alc883_sixstack_ch6_init[] = {
7727 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7728 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7729 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7730 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7731 { } /* end */
7732};
7733
7734/*
7735 * 8ch mode
7736 */
7737static struct hda_verb alc883_sixstack_ch8_init[] = {
7738 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7739 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7740 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7741 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7742 { } /* end */
7743};
7744
7745static struct hda_channel_mode alc883_sixstack_modes[2] = {
7746 { 6, alc883_sixstack_ch6_init },
7747 { 8, alc883_sixstack_ch8_init },
7748};
7749
7750
Linus Torvalds1da177e2005-04-16 15:20:36 -07007751/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
7752 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
7753 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01007754static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02007755 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007756 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007757 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007758 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007759 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7760 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007761 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7762 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007763 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007764 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007765 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7766 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7767 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7768 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7769 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7770 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007771 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007772 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7773 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007774 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007775 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007776 { } /* end */
7777};
7778
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08007779/* Macbook Air 2,1 same control for HP and internal Speaker */
7780
7781static struct snd_kcontrol_new alc885_mba21_mixer[] = {
7782 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7783 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT),
7784 { }
7785};
7786
7787
Takashi Iwai87350ad2007-08-16 18:19:38 +02007788static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwaia3f730af2009-08-31 08:15:26 +02007789 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7790 HDA_BIND_MUTE ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
7791 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7792 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT),
7793 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01007794 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7795 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02007796 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
7797 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01007798 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02007799 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
7800 { } /* end */
7801};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007802
7803static struct snd_kcontrol_new alc885_mb5_mixer[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007804 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7805 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
7806 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
7807 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
7808 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7809 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
Alex Murraya76221d2010-01-13 23:15:03 +10307810 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
7811 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
Alex Murrayb8f171e2010-06-14 12:08:43 +09307812 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
7813 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007814 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
7815 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
7816 HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT),
7817 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0x00, HDA_INPUT),
7818 { } /* end */
7819};
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007820
Luke Yelaviche458b1f2010-02-12 16:28:29 +11007821static struct snd_kcontrol_new alc885_macmini3_mixer[] = {
7822 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7823 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
7824 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
7825 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
7826 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7827 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
7828 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
7829 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
7830 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
7831 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
7832 HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT),
7833 { } /* end */
7834};
7835
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08007836static struct snd_kcontrol_new alc885_imac91_mixer[] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07007837 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7838 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08007839 { } /* end */
7840};
7841
7842
Kailang Yangbdd148a2007-05-08 15:19:08 +02007843static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
7844 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7845 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7846 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7847 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7848 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7849 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7850 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7851 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7852 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02007853 { } /* end */
7854};
7855
Kailang Yang272a5272007-05-14 11:00:38 +02007856static struct snd_kcontrol_new alc882_targa_mixer[] = {
7857 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7858 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7859 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7860 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7861 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7862 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7863 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7864 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7865 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02007866 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007867 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7868 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02007869 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007870 { } /* end */
7871};
7872
7873/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
7874 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
7875 */
7876static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
7877 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7878 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7879 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7880 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
7881 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7882 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7883 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7884 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7885 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
7886 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
7887 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7888 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02007889 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007890 { } /* end */
7891};
7892
Takashi Iwai914759b2007-09-06 14:52:04 +02007893static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
7894 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7895 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7896 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7897 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7898 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7899 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7900 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7901 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7902 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7903 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02007904 { } /* end */
7905};
7906
Kailang Yangdf694da2005-12-05 19:42:22 +01007907static struct snd_kcontrol_new alc882_chmode_mixer[] = {
7908 {
7909 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7910 .name = "Channel Mode",
7911 .info = alc_ch_mode_info,
7912 .get = alc_ch_mode_get,
7913 .put = alc_ch_mode_put,
7914 },
7915 { } /* end */
7916};
7917
Takashi Iwai4953550a2009-06-30 15:28:30 +02007918static struct hda_verb alc882_base_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007919 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007920 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7921 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007922 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02007923 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7924 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007925 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02007926 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7927 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007928 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02007929 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7930 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007931
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007932 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007933 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007934 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007935 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007936 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007937 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007938 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007939 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007940 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007941 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007942 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007943 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007944 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007945 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007946 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007947 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007948 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02007949 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007950 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7951 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02007952 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007953 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7954 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02007955 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007956 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7957 /* Line-2 In: Headphone output (output 0 - 0x0c) */
7958 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7959 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7960 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007961 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02007962 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007963
7964 /* FIXME: use matrix-type input source selection */
7965 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007966 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02007967 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007968 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02007969 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai05acb862005-06-10 19:50:25 +02007970 /* ADC2: mute amp left and right */
7971 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02007972 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02007973 /* ADC3: mute amp left and right */
7974 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02007975 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007976
7977 { }
7978};
7979
Takashi Iwai4953550a2009-06-30 15:28:30 +02007980static struct hda_verb alc882_adc1_init_verbs[] = {
7981 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
7982 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7983 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7984 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7985 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7986 /* ADC1: mute amp left and right */
7987 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7988 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
7989 { }
7990};
7991
Takashi Iwai4b146cb2006-07-28 14:42:36 +02007992static struct hda_verb alc882_eapd_verbs[] = {
7993 /* change to EAPD mode */
7994 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007995 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007996 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02007997};
7998
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007999static struct hda_verb alc889_eapd_verbs[] = {
8000 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
8001 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
8002 { }
8003};
8004
Wu Fengguang6732bd02009-07-30 09:19:14 +02008005static struct hda_verb alc_hp15_unsol_verbs[] = {
8006 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8007 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8008 {}
8009};
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008010
8011static struct hda_verb alc885_init_verbs[] = {
8012 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Kailang Yang88102f32010-02-04 14:12:58 +01008013 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8014 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008015 /* Rear mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008016 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8017 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008018 /* CLFE mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008019 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8020 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008021 /* Side mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008022 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8023 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008024
8025 /* Front HP Pin: output 0 (0x0c) */
Wu Fengguang6732bd02009-07-30 09:19:14 +02008026 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008027 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8028 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8029 /* Front Pin: output 0 (0x0c) */
8030 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8031 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8032 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8033 /* Rear Pin: output 1 (0x0d) */
8034 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8035 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8036 {0x19, AC_VERB_SET_CONNECT_SEL, 0x01},
8037 /* CLFE Pin: output 2 (0x0e) */
8038 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8039 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8040 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
8041 /* Side Pin: output 3 (0x0f) */
8042 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8043 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8044 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
8045 /* Mic (rear) pin: input vref at 80% */
8046 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8047 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8048 /* Front Mic pin: input vref at 80% */
8049 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8050 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8051 /* Line In pin: input */
8052 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8053 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8054
8055 /* Mixer elements: 0x18, , 0x1a, 0x1b */
8056 /* Input mixer1 */
Kailang Yang88102f32010-02-04 14:12:58 +01008057 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008058 /* Input mixer2 */
8059 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008060 /* Input mixer3 */
Kailang Yang88102f32010-02-04 14:12:58 +01008061 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008062 /* ADC2: mute amp left and right */
8063 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8064 /* ADC3: mute amp left and right */
8065 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8066
8067 { }
8068};
8069
8070static struct hda_verb alc885_init_input_verbs[] = {
8071 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8072 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
8073 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
8074 { }
8075};
8076
8077
8078/* Unmute Selector 24h and set the default input to front mic */
8079static struct hda_verb alc889_init_input_verbs[] = {
8080 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
8081 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8082 { }
8083};
8084
8085
Takashi Iwai4953550a2009-06-30 15:28:30 +02008086#define alc883_init_verbs alc882_base_init_verbs
8087
Tobin Davis9102cd12006-12-15 10:02:12 +01008088/* Mac Pro test */
8089static struct snd_kcontrol_new alc882_macpro_mixer[] = {
8090 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8091 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8092 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
8093 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
8094 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01008095 /* FIXME: this looks suspicious...
Jaroslav Kyselad355c82a2009-11-03 15:47:25 +01008096 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT),
8097 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01008098 */
Tobin Davis9102cd12006-12-15 10:02:12 +01008099 { } /* end */
8100};
8101
8102static struct hda_verb alc882_macpro_init_verbs[] = {
8103 /* Front mixer: unmute input/output amp left and right (volume = 0) */
8104 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8105 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8106 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8107 /* Front Pin: output 0 (0x0c) */
8108 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8109 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8110 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8111 /* Front Mic pin: input vref at 80% */
8112 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8113 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8114 /* Speaker: output */
8115 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8116 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8117 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
8118 /* Headphone output (output 0 - 0x0c) */
8119 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8120 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8121 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8122
8123 /* FIXME: use matrix-type input source selection */
8124 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8125 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8126 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8127 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8128 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8129 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8130 /* Input mixer2 */
8131 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8132 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8133 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8134 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8135 /* Input mixer3 */
8136 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8137 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8138 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8139 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8140 /* ADC1: mute amp left and right */
8141 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8142 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8143 /* ADC2: mute amp left and right */
8144 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8145 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8146 /* ADC3: mute amp left and right */
8147 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8148 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8149
8150 { }
8151};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008152
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008153/* Macbook 5,1 */
8154static struct hda_verb alc885_mb5_init_verbs[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008155 /* DACs */
8156 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8157 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8158 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8159 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008160 /* Front mixer */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008161 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8162 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8163 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008164 /* Surround mixer */
8165 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8166 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8167 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8168 /* LFE mixer */
8169 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8170 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8171 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8172 /* HP mixer */
8173 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8174 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8175 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8176 /* Front Pin (0x0c) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008177 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8178 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008179 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8180 /* LFE Pin (0x0e) */
8181 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8182 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8183 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
8184 /* HP Pin (0x0f) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008185 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8186 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008187 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
Alex Murraya76221d2010-01-13 23:15:03 +10308188 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008189 /* Front Mic pin: input vref at 80% */
8190 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8191 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8192 /* Line In pin */
8193 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8194 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8195
Alex Murrayb8f171e2010-06-14 12:08:43 +09308196 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0x1)},
8197 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x7)},
8198 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x4)},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008199 { }
8200};
8201
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008202/* Macmini 3,1 */
8203static struct hda_verb alc885_macmini3_init_verbs[] = {
8204 /* DACs */
8205 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8206 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8207 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8208 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8209 /* Front mixer */
8210 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8211 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8212 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8213 /* Surround mixer */
8214 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8215 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8216 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8217 /* LFE mixer */
8218 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8219 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8220 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8221 /* HP mixer */
8222 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8223 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8224 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8225 /* Front Pin (0x0c) */
8226 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8227 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8228 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8229 /* LFE Pin (0x0e) */
8230 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8231 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8232 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
8233 /* HP Pin (0x0f) */
8234 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8235 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8236 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
8237 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8238 /* Line In pin */
8239 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8240 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8241
8242 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8243 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8244 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8245 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8246 { }
8247};
8248
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008249
8250static struct hda_verb alc885_mba21_init_verbs[] = {
8251 /*Internal and HP Speaker Mixer*/
8252 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8253 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8254 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8255 /*Internal Speaker Pin (0x0c)*/
8256 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8257 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8258 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8259 /* HP Pin: output 0 (0x0e) */
8260 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
8261 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8262 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8263 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
8264 /* Line in (is hp when jack connected)*/
8265 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
8266 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8267
8268 { }
8269 };
8270
8271
Takashi Iwai87350ad2007-08-16 18:19:38 +02008272/* Macbook Pro rev3 */
8273static struct hda_verb alc885_mbp3_init_verbs[] = {
8274 /* Front mixer: unmute input/output amp left and right (volume = 0) */
8275 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8276 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8277 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8278 /* Rear mixer */
8279 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8280 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8281 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaia3f730af2009-08-31 08:15:26 +02008282 /* HP mixer */
8283 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8284 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8285 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai87350ad2007-08-16 18:19:38 +02008286 /* Front Pin: output 0 (0x0c) */
8287 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8288 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8289 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaia3f730af2009-08-31 08:15:26 +02008290 /* HP Pin: output 0 (0x0e) */
Takashi Iwai87350ad2007-08-16 18:19:38 +02008291 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
Takashi Iwaia3f730af2009-08-31 08:15:26 +02008292 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8293 {0x15, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai87350ad2007-08-16 18:19:38 +02008294 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8295 /* Mic (rear) pin: input vref at 80% */
8296 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8297 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8298 /* Front Mic pin: input vref at 80% */
8299 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8300 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8301 /* Line In pin: use output 1 when in LineOut mode */
8302 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8303 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8304 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
8305
8306 /* FIXME: use matrix-type input source selection */
8307 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8308 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8309 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8310 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8311 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8312 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8313 /* Input mixer2 */
8314 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8315 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8316 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8317 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8318 /* Input mixer3 */
8319 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8320 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8321 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8322 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8323 /* ADC1: mute amp left and right */
8324 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8325 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8326 /* ADC2: mute amp left and right */
8327 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8328 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8329 /* ADC3: mute amp left and right */
8330 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8331 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8332
8333 { }
8334};
8335
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008336/* iMac 9,1 */
8337static struct hda_verb alc885_imac91_init_verbs[] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008338 /* Internal Speaker Pin (0x0c) */
8339 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8340 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8341 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8342 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8343 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8344 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8345 /* HP Pin: Rear */
8346 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8347 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8348 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8349 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
8350 /* Line in Rear */
8351 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
8352 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8353 /* Front Mic pin: input vref at 80% */
8354 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8355 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008356 /* Rear mixer */
8357 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8358 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8359 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008360 /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */
8361 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8362 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8363 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8364 /* 0x24 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008365 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8366 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8367 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8368 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008369 /* 0x23 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008370 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8371 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8372 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8373 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008374 /* 0x22 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008375 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8376 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8377 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8378 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008379 /* 0x07 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008380 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8381 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008382 /* 0x08 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008383 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8384 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008385 /* 0x09 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008386 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8387 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008388 { }
8389};
8390
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008391/* iMac 24 mixer. */
8392static struct snd_kcontrol_new alc885_imac24_mixer[] = {
8393 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8394 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
8395 { } /* end */
8396};
8397
8398/* iMac 24 init verbs. */
8399static struct hda_verb alc885_imac24_init_verbs[] = {
8400 /* Internal speakers: output 0 (0x0c) */
8401 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8402 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8403 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8404 /* Internal speakers: output 0 (0x0c) */
8405 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8406 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8407 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8408 /* Headphone: output 0 (0x0c) */
8409 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8410 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8411 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8412 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8413 /* Front Mic: input vref at 80% */
8414 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8415 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8416 { }
8417};
8418
8419/* Toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008420static void alc885_imac24_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008421{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008422 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008423
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008424 spec->autocfg.hp_pins[0] = 0x14;
8425 spec->autocfg.speaker_pins[0] = 0x18;
8426 spec->autocfg.speaker_pins[1] = 0x1a;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008427}
8428
Takashi Iwai9d54f082010-02-22 08:34:40 +01008429#define alc885_mb5_setup alc885_imac24_setup
8430#define alc885_macmini3_setup alc885_imac24_setup
8431
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008432/* Macbook Air 2,1 */
8433static void alc885_mba21_setup(struct hda_codec *codec)
8434{
8435 struct alc_spec *spec = codec->spec;
8436
8437 spec->autocfg.hp_pins[0] = 0x14;
8438 spec->autocfg.speaker_pins[0] = 0x18;
8439}
8440
8441
8442
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008443static void alc885_mbp3_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008444{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008445 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008446
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008447 spec->autocfg.hp_pins[0] = 0x15;
8448 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai87350ad2007-08-16 18:19:38 +02008449}
8450
Takashi Iwai9d54f082010-02-22 08:34:40 +01008451static void alc885_imac91_setup(struct hda_codec *codec)
Alex Murraya76221d2010-01-13 23:15:03 +10308452{
Takashi Iwai9d54f082010-02-22 08:34:40 +01008453 struct alc_spec *spec = codec->spec;
Alex Murraya76221d2010-01-13 23:15:03 +10308454
Takashi Iwai9d54f082010-02-22 08:34:40 +01008455 spec->autocfg.hp_pins[0] = 0x14;
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008456 spec->autocfg.speaker_pins[0] = 0x18;
Takashi Iwai9d54f082010-02-22 08:34:40 +01008457 spec->autocfg.speaker_pins[1] = 0x1a;
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008458}
Takashi Iwai87350ad2007-08-16 18:19:38 +02008459
Kailang Yang272a5272007-05-14 11:00:38 +02008460static struct hda_verb alc882_targa_verbs[] = {
8461 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8462 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8463
8464 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8465 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008466
Kailang Yang272a5272007-05-14 11:00:38 +02008467 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8468 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8469 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8470
8471 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yang272a5272007-05-14 11:00:38 +02008472 { } /* end */
8473};
8474
8475/* toggle speaker-output according to the hp-jack state */
8476static void alc882_targa_automute(struct hda_codec *codec)
8477{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008478 struct alc_spec *spec = codec->spec;
8479 alc_automute_amp(codec);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02008480 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008481 spec->jack_present ? 1 : 3);
8482}
8483
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008484static void alc882_targa_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008485{
8486 struct alc_spec *spec = codec->spec;
8487
8488 spec->autocfg.hp_pins[0] = 0x14;
8489 spec->autocfg.speaker_pins[0] = 0x1b;
Kailang Yang272a5272007-05-14 11:00:38 +02008490}
8491
8492static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
8493{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008494 if ((res >> 26) == ALC880_HP_EVENT)
Kailang Yang272a5272007-05-14 11:00:38 +02008495 alc882_targa_automute(codec);
Kailang Yang272a5272007-05-14 11:00:38 +02008496}
8497
8498static struct hda_verb alc882_asus_a7j_verbs[] = {
8499 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8500 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8501
8502 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8503 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8504 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008505
Kailang Yang272a5272007-05-14 11:00:38 +02008506 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8507 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8508 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8509
8510 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8511 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8512 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8513 { } /* end */
8514};
8515
Takashi Iwai914759b2007-09-06 14:52:04 +02008516static struct hda_verb alc882_asus_a7m_verbs[] = {
8517 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8518 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8519
8520 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8521 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8522 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008523
Takashi Iwai914759b2007-09-06 14:52:04 +02008524 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8525 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8526 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8527
8528 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8529 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8530 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8531 { } /* end */
8532};
8533
Tobin Davis9102cd12006-12-15 10:02:12 +01008534static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
8535{
8536 unsigned int gpiostate, gpiomask, gpiodir;
8537
8538 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
8539 AC_VERB_GET_GPIO_DATA, 0);
8540
8541 if (!muted)
8542 gpiostate |= (1 << pin);
8543 else
8544 gpiostate &= ~(1 << pin);
8545
8546 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
8547 AC_VERB_GET_GPIO_MASK, 0);
8548 gpiomask |= (1 << pin);
8549
8550 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
8551 AC_VERB_GET_GPIO_DIRECTION, 0);
8552 gpiodir |= (1 << pin);
8553
8554
8555 snd_hda_codec_write(codec, codec->afg, 0,
8556 AC_VERB_SET_GPIO_MASK, gpiomask);
8557 snd_hda_codec_write(codec, codec->afg, 0,
8558 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
8559
8560 msleep(1);
8561
8562 snd_hda_codec_write(codec, codec->afg, 0,
8563 AC_VERB_SET_GPIO_DATA, gpiostate);
8564}
8565
Takashi Iwai7debbe52007-08-16 15:01:03 +02008566/* set up GPIO at initialization */
8567static void alc885_macpro_init_hook(struct hda_codec *codec)
8568{
8569 alc882_gpio_mute(codec, 0, 0);
8570 alc882_gpio_mute(codec, 1, 0);
8571}
8572
8573/* set up GPIO and update auto-muting at initialization */
8574static void alc885_imac24_init_hook(struct hda_codec *codec)
8575{
8576 alc885_macpro_init_hook(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008577 alc_automute_amp(codec);
Takashi Iwai7debbe52007-08-16 15:01:03 +02008578}
8579
Kailang Yangdf694da2005-12-05 19:42:22 +01008580/*
8581 * generic initialization of ADC, input mixers and output mixers
8582 */
Takashi Iwai4953550a2009-06-30 15:28:30 +02008583static struct hda_verb alc883_auto_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01008584 /*
8585 * Unmute ADC0-2 and set the default input to mic-in
8586 */
Kailang Yangdf694da2005-12-05 19:42:22 +01008587 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8588 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8589 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8590 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8591
Kailang Yangdf694da2005-12-05 19:42:22 +01008592 /*
8593 * Set up output mixers (0x0c - 0x0f)
8594 */
8595 /* set vol=0 to output mixers */
8596 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8597 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8598 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8599 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8600 /* set up input amps for analog loopback */
8601 /* Amp Indices: DAC = 0, mixer = 1 */
8602 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8603 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8604 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8605 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8606 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8607 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8608 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8609 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8610 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8611 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8612
8613 /* FIXME: use matrix-type input source selection */
8614 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Kailang Yangdf694da2005-12-05 19:42:22 +01008615 /* Input mixer2 */
Kailang Yang88102f32010-02-04 14:12:58 +01008616 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008617 /* Input mixer3 */
Kailang Yang88102f32010-02-04 14:12:58 +01008618 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008619 { }
8620};
8621
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008622/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
8623static struct hda_verb alc889A_mb31_ch2_init[] = {
8624 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
8625 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8626 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
8627 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
8628 { } /* end */
8629};
8630
8631/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */
8632static struct hda_verb alc889A_mb31_ch4_init[] = {
8633 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
8634 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8635 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
8636 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
8637 { } /* end */
8638};
8639
8640/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */
8641static struct hda_verb alc889A_mb31_ch5_init[] = {
8642 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */
8643 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8644 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
8645 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
8646 { } /* end */
8647};
8648
8649/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */
8650static struct hda_verb alc889A_mb31_ch6_init[] = {
8651 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */
8652 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */
8653 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
8654 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
8655 { } /* end */
8656};
8657
8658static struct hda_channel_mode alc889A_mb31_6ch_modes[4] = {
8659 { 2, alc889A_mb31_ch2_init },
8660 { 4, alc889A_mb31_ch4_init },
8661 { 5, alc889A_mb31_ch5_init },
8662 { 6, alc889A_mb31_ch6_init },
8663};
8664
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008665static struct hda_verb alc883_medion_eapd_verbs[] = {
8666 /* eanable EAPD on medion laptop */
8667 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8668 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
8669 { }
8670};
8671
Takashi Iwai4953550a2009-06-30 15:28:30 +02008672#define alc883_base_mixer alc882_base_mixer
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008673
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008674static struct snd_kcontrol_new alc883_mitac_mixer[] = {
8675 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8676 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8677 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8678 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8679 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8680 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8681 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8682 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8683 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8684 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8685 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8686 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
8687 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008688 { } /* end */
8689};
8690
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008691static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01008692 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8693 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8694 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8695 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8696 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8697 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8698 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8699 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8700 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8701 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01008702 { } /* end */
8703};
8704
Jiang zhefb97dc62008-03-06 11:07:11 +01008705static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
8706 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8707 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8708 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8709 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8710 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8711 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8712 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8713 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8714 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8715 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01008716 { } /* end */
8717};
8718
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008719static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
8720 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8721 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8722 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8723 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8724 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8725 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8726 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8727 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008728 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008729 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8730 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008731 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008732 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008733 { } /* end */
8734};
8735
8736static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
8737 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8738 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8739 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8740 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8741 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8742 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8743 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8744 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8745 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8746 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8747 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8748 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8749 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8750 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008751 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008752 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8753 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008754 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008755 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008756 { } /* end */
8757};
8758
Jiang zhe17bba1b2008-06-04 12:11:07 +02008759static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
8760 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8761 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8762 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8763 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8764 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
8765 HDA_OUTPUT),
8766 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8767 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8768 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8769 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8770 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8771 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8772 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8773 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8774 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8775 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
8776 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8777 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8778 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
8779 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008780 { } /* end */
8781};
8782
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008783static struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
8784 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8785 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8786 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8787 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8788 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
8789 HDA_OUTPUT),
8790 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8791 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8792 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8793 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8794 HDA_BIND_MUTE("Speaker Playback Switch", 0x0f, 2, HDA_INPUT),
8795 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8796 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8797 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8798 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
8799 HDA_CODEC_VOLUME("Mic Boost", 0x1b, 0, HDA_INPUT),
8800 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
8801 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8802 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
8803 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8804 { } /* end */
8805};
8806
Takashi Iwaid1d985f2006-11-23 19:27:12 +01008807static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02008808 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008809 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008810 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008811 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008812 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8813 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008814 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8815 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008816 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8817 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8818 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8819 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8820 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8821 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008822 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008823 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8824 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008825 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008826 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008827 { } /* end */
8828};
8829
Sasha Alexandrc2592492009-06-16 14:52:54 -04008830static struct snd_kcontrol_new alc883_targa_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02008831 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008832 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008833 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008834 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008835 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8836 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8837 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8838 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8839 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8840 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8841 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8842 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8843 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8844 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8845 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008846 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008847 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008848 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008849};
Kailang Yangccc656c2006-10-17 12:32:26 +02008850
Sasha Alexandrc2592492009-06-16 14:52:54 -04008851static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02008852 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008853 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008854 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008855 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008856 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8857 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8858 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008859 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008860 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe4383fae2008-04-14 12:58:57 +02008861 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8862 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8863 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008864 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008865};
Kailang Yangccc656c2006-10-17 12:32:26 +02008866
Takashi Iwaib99dba32009-09-17 18:23:00 +02008867static struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
8868 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8869 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
8870 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8871 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8872 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8873 { } /* end */
8874};
8875
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008876static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
8877 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8878 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01008879 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8880 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008881 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8882 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8883 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8884 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008885 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008886};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008887
Kailang Yang272a5272007-05-14 11:00:38 +02008888static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
8889 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8890 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
8891 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8892 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8893 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8894 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8895 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson150b4322010-07-29 14:46:42 +02008896 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8897 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008898 { } /* end */
8899};
8900
8901static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
8902 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8903 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8904 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8905 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8906 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8907 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8908 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8909 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8910 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008911 { } /* end */
Kailang Yangea1fb292008-08-26 12:58:38 +02008912};
Kailang Yang272a5272007-05-14 11:00:38 +02008913
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02008914static struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = {
8915 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8916 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8917 HDA_CODEC_MUTE("Speaker Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8918 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
8919 HDA_CODEC_VOLUME("Line Playback Volume", 0x08, 0x0, HDA_INPUT),
8920 HDA_CODEC_MUTE("Line Playback Switch", 0x08, 0x0, HDA_INPUT),
8921 { } /* end */
8922};
8923
8924static struct hda_verb alc883_medion_wim2160_verbs[] = {
8925 /* Unmute front mixer */
8926 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8927 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8928
8929 /* Set speaker pin to front mixer */
8930 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8931
8932 /* Init headphone pin */
8933 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8934 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8935 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8936 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8937
8938 { } /* end */
8939};
8940
8941/* toggle speaker-output according to the hp-jack state */
8942static void alc883_medion_wim2160_setup(struct hda_codec *codec)
8943{
8944 struct alc_spec *spec = codec->spec;
8945
8946 spec->autocfg.hp_pins[0] = 0x1a;
8947 spec->autocfg.speaker_pins[0] = 0x15;
8948}
8949
Tobin Davis2880a862007-08-07 11:50:26 +02008950static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02008951 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8952 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02008953 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02008954 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8955 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02008956 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8957 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8958 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02008959 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02008960};
Tobin Davis2880a862007-08-07 11:50:26 +02008961
Tony Vroond2fd4b02009-06-21 00:40:10 +01008962static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
8963 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01008964 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Tony Vroon684a8842009-06-26 09:27:50 +01008965 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8966 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01008967 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8968 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8969 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8970 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8971 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8972 { } /* end */
8973};
8974
Kailang Yange2757d52008-08-26 13:17:46 +02008975static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
8976 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8977 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8978 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
8979 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
8980 HDA_CODEC_VOLUME_MONO("Center Playback Volume",
8981 0x0d, 1, 0x0, HDA_OUTPUT),
8982 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
8983 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
8984 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
8985 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8986 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02008987 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8988 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8989 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8990 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8991 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8992 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8993 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8994 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8995 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
8996 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02008997 { } /* end */
8998};
8999
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009000static struct snd_kcontrol_new alc889A_mb31_mixer[] = {
9001 /* Output mixers */
9002 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
9003 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
9004 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
9005 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
9006 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00,
9007 HDA_OUTPUT),
9008 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT),
9009 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT),
9010 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT),
9011 /* Output switches */
9012 HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT),
9013 HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT),
9014 HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT),
9015 /* Boost mixers */
9016 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
9017 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
9018 /* Input mixers */
9019 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
9020 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
9021 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9022 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9023 { } /* end */
9024};
9025
Guido Günther3e1647c52009-06-05 00:47:26 +02009026static struct snd_kcontrol_new alc883_vaiott_mixer[] = {
9027 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9028 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9029 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9030 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
9031 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
9032 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
9033 { } /* end */
9034};
9035
Kailang Yange2757d52008-08-26 13:17:46 +02009036static struct hda_bind_ctls alc883_bind_cap_vol = {
9037 .ops = &snd_hda_bind_vol,
9038 .values = {
9039 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
9040 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
9041 0
9042 },
9043};
9044
9045static struct hda_bind_ctls alc883_bind_cap_switch = {
9046 .ops = &snd_hda_bind_sw,
9047 .values = {
9048 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
9049 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
9050 0
9051 },
9052};
9053
9054static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
9055 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9056 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9057 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9058 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9059 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9060 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9061 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9062 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009063 { } /* end */
9064};
9065
9066static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009067 HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
9068 HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
9069 {
9070 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9071 /* .name = "Capture Source", */
9072 .name = "Input Source",
9073 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01009074 .info = alc_mux_enum_info,
9075 .get = alc_mux_enum_get,
9076 .put = alc_mux_enum_put,
Kailang Yange2757d52008-08-26 13:17:46 +02009077 },
9078 { } /* end */
9079};
9080
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009081static struct snd_kcontrol_new alc883_chmode_mixer[] = {
9082 {
9083 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9084 .name = "Channel Mode",
9085 .info = alc_ch_mode_info,
9086 .get = alc_ch_mode_get,
9087 .put = alc_ch_mode_put,
9088 },
9089 { } /* end */
9090};
9091
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009092/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009093static void alc883_mitac_setup(struct hda_codec *codec)
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009094{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009095 struct alc_spec *spec = codec->spec;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009096
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009097 spec->autocfg.hp_pins[0] = 0x15;
9098 spec->autocfg.speaker_pins[0] = 0x14;
9099 spec->autocfg.speaker_pins[1] = 0x17;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009100}
9101
9102/* auto-toggle front mic */
9103/*
9104static void alc883_mitac_mic_automute(struct hda_codec *codec)
9105{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009106 unsigned char bits = snd_hda_jack_detect(codec, 0x18) ? HDA_AMP_MUTE : 0;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009107
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009108 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
9109}
9110*/
9111
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009112static struct hda_verb alc883_mitac_verbs[] = {
9113 /* HP */
9114 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9115 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9116 /* Subwoofer */
9117 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
9118 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9119
9120 /* enable unsolicited event */
9121 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9122 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
9123
9124 { } /* end */
9125};
9126
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309127static struct hda_verb alc883_clevo_m540r_verbs[] = {
9128 /* HP */
9129 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9130 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9131 /* Int speaker */
9132 /*{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},*/
9133
9134 /* enable unsolicited event */
9135 /*
9136 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9137 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
9138 */
9139
9140 { } /* end */
9141};
9142
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009143static struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01009144 /* HP */
9145 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9146 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9147 /* Int speaker */
9148 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
9149 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9150
9151 /* enable unsolicited event */
9152 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009153 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01009154
9155 { } /* end */
9156};
9157
Jiang zhefb97dc62008-03-06 11:07:11 +01009158static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
9159 /* HP */
9160 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9161 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9162 /* Subwoofer */
9163 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
9164 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9165
9166 /* enable unsolicited event */
9167 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9168
9169 { } /* end */
9170};
9171
Sasha Alexandrc2592492009-06-16 14:52:54 -04009172static struct hda_verb alc883_targa_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02009173 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9174 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9175
9176 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9177 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02009178
David Heidelberger64a8be72009-06-08 16:15:18 +02009179/* Connect Line-Out side jack (SPDIF) to Side */
9180 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9181 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9182 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
9183/* Connect Mic jack to CLFE */
9184 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9185 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9186 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
9187/* Connect Line-in jack to Surround */
9188 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9189 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9190 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
9191/* Connect HP out jack to Front */
9192 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9193 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9194 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangccc656c2006-10-17 12:32:26 +02009195
9196 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangccc656c2006-10-17 12:32:26 +02009197
9198 { } /* end */
9199};
9200
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009201static struct hda_verb alc883_lenovo_101e_verbs[] = {
9202 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9203 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
9204 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
9205 { } /* end */
9206};
9207
Kailang Yang272a5272007-05-14 11:00:38 +02009208static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
9209 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9210 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9211 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9212 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9213 { } /* end */
9214};
9215
9216static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
9217 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9218 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9219 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9220 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
9221 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9222 { } /* end */
9223};
9224
Kailang Yang189609a2007-08-20 11:31:23 +02009225static struct hda_verb alc883_haier_w66_verbs[] = {
9226 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9227 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9228
9229 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9230
9231 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9232 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9233 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9234 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9235 { } /* end */
9236};
9237
Kailang Yange2757d52008-08-26 13:17:46 +02009238static struct hda_verb alc888_lenovo_sky_verbs[] = {
9239 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9240 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9241 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9242 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9243 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9244 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9245 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
9246 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9247 { } /* end */
9248};
9249
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009250static struct hda_verb alc888_6st_dell_verbs[] = {
9251 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9252 { }
9253};
9254
Guido Günther3e1647c52009-06-05 00:47:26 +02009255static struct hda_verb alc883_vaiott_verbs[] = {
9256 /* HP */
9257 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9258 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9259
9260 /* enable unsolicited event */
9261 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9262
9263 { } /* end */
9264};
9265
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009266static void alc888_3st_hp_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009267{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009268 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009269
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009270 spec->autocfg.hp_pins[0] = 0x1b;
9271 spec->autocfg.speaker_pins[0] = 0x14;
9272 spec->autocfg.speaker_pins[1] = 0x16;
9273 spec->autocfg.speaker_pins[2] = 0x18;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009274}
9275
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009276static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009277 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01009278 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
9279 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009280 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009281 { } /* end */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009282};
9283
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009284/*
9285 * 2ch mode
9286 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009287static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009288 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9289 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9290 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
9291 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009292 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009293};
9294
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009295/*
9296 * 4ch mode
9297 */
9298static struct hda_verb alc888_3st_hp_4ch_init[] = {
9299 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9300 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9301 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9302 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9303 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
9304 { } /* end */
9305};
9306
9307/*
9308 * 6ch mode
9309 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009310static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009311 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9312 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009313 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009314 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9315 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009316 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
9317 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009318};
9319
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009320static struct hda_channel_mode alc888_3st_hp_modes[3] = {
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009321 { 2, alc888_3st_hp_2ch_init },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009322 { 4, alc888_3st_hp_4ch_init },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009323 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009324};
9325
Kailang Yang272a5272007-05-14 11:00:38 +02009326/* toggle front-jack and RCA according to the hp-jack state */
9327static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
9328{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009329 unsigned int present = snd_hda_jack_detect(codec, 0x1b);
Kailang Yangea1fb292008-08-26 12:58:38 +02009330
Takashi Iwai47fd8302007-08-10 17:11:07 +02009331 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9332 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9333 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9334 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02009335}
9336
9337/* toggle RCA according to the front-jack state */
9338static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
9339{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009340 unsigned int present = snd_hda_jack_detect(codec, 0x14);
Kailang Yangea1fb292008-08-26 12:58:38 +02009341
Takashi Iwai47fd8302007-08-10 17:11:07 +02009342 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9343 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02009344}
Takashi Iwai47fd8302007-08-10 17:11:07 +02009345
Kailang Yang272a5272007-05-14 11:00:38 +02009346static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
9347 unsigned int res)
9348{
9349 if ((res >> 26) == ALC880_HP_EVENT)
9350 alc888_lenovo_ms7195_front_automute(codec);
9351 if ((res >> 26) == ALC880_FRONT_EVENT)
9352 alc888_lenovo_ms7195_rca_automute(codec);
9353}
9354
9355static struct hda_verb alc883_medion_md2_verbs[] = {
9356 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9357 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9358
9359 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9360
9361 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9362 { } /* end */
9363};
9364
9365/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009366static void alc883_medion_md2_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +02009367{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009368 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009369
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009370 spec->autocfg.hp_pins[0] = 0x14;
9371 spec->autocfg.speaker_pins[0] = 0x15;
Kailang Yang272a5272007-05-14 11:00:38 +02009372}
9373
Kailang Yangccc656c2006-10-17 12:32:26 +02009374/* toggle speaker-output according to the hp-jack state */
Sasha Alexandrc2592492009-06-16 14:52:54 -04009375#define alc883_targa_init_hook alc882_targa_init_hook
9376#define alc883_targa_unsol_event alc882_targa_unsol_event
Jiang zhe368c7a92008-03-04 11:20:33 +01009377
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009378static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
9379{
9380 unsigned int present;
9381
Takashi Iwaid56757a2009-11-18 08:00:14 +01009382 present = snd_hda_jack_detect(codec, 0x18);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009383 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
9384 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9385}
9386
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009387static void alc883_clevo_m720_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009388{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009389 struct alc_spec *spec = codec->spec;
9390
9391 spec->autocfg.hp_pins[0] = 0x15;
9392 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009393}
9394
9395static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
9396{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009397 alc_automute_amp(codec);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009398 alc883_clevo_m720_mic_automute(codec);
9399}
9400
9401static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01009402 unsigned int res)
9403{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009404 switch (res >> 26) {
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009405 case ALC880_MIC_EVENT:
9406 alc883_clevo_m720_mic_automute(codec);
9407 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009408 default:
9409 alc_automute_amp_unsol_event(codec, res);
9410 break;
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009411 }
Jiang zhe368c7a92008-03-04 11:20:33 +01009412}
9413
Jiang zhefb97dc62008-03-06 11:07:11 +01009414/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009415static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01009416{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009417 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01009418
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009419 spec->autocfg.hp_pins[0] = 0x14;
9420 spec->autocfg.speaker_pins[0] = 0x15;
Jiang zhefb97dc62008-03-06 11:07:11 +01009421}
9422
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009423static void alc883_haier_w66_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01009424{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009425 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01009426
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009427 spec->autocfg.hp_pins[0] = 0x1b;
9428 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang189609a2007-08-20 11:31:23 +02009429}
9430
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009431static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
9432{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009433 int bits = snd_hda_jack_detect(codec, 0x14) ? HDA_AMP_MUTE : 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009434
Takashi Iwai47fd8302007-08-10 17:11:07 +02009435 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9436 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009437}
9438
9439static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
9440{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009441 int bits = snd_hda_jack_detect(codec, 0x1b) ? HDA_AMP_MUTE : 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009442
Takashi Iwai47fd8302007-08-10 17:11:07 +02009443 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9444 HDA_AMP_MUTE, bits);
9445 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9446 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009447}
9448
9449static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
9450 unsigned int res)
9451{
9452 if ((res >> 26) == ALC880_HP_EVENT)
9453 alc883_lenovo_101e_all_automute(codec);
9454 if ((res >> 26) == ALC880_FRONT_EVENT)
9455 alc883_lenovo_101e_ispeaker_automute(codec);
9456}
9457
Takashi Iwai676a9b52007-08-16 15:23:35 +02009458/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009459static void alc883_acer_aspire_setup(struct hda_codec *codec)
Takashi Iwai676a9b52007-08-16 15:23:35 +02009460{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009461 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009462
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009463 spec->autocfg.hp_pins[0] = 0x14;
9464 spec->autocfg.speaker_pins[0] = 0x15;
9465 spec->autocfg.speaker_pins[1] = 0x16;
Takashi Iwai676a9b52007-08-16 15:23:35 +02009466}
9467
Kailang Yangd1a991a2007-08-15 16:21:59 +02009468static struct hda_verb alc883_acer_eapd_verbs[] = {
9469 /* HP Pin: output 0 (0x0c) */
9470 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9471 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9472 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9473 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02009474 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9475 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009476 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009477 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
9478 /* eanable EAPD on medion laptop */
9479 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
9480 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02009481 /* enable unsolicited event */
9482 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009483 { }
9484};
9485
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009486static struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
9487 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9488 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
9489 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9490 { } /* end */
9491};
9492
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009493static void alc888_6st_dell_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009494{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009495 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009496
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009497 spec->autocfg.hp_pins[0] = 0x1b;
9498 spec->autocfg.speaker_pins[0] = 0x14;
9499 spec->autocfg.speaker_pins[1] = 0x15;
9500 spec->autocfg.speaker_pins[2] = 0x16;
9501 spec->autocfg.speaker_pins[3] = 0x17;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009502}
9503
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009504static void alc888_lenovo_sky_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009505{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009506 struct alc_spec *spec = codec->spec;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009507
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009508 spec->autocfg.hp_pins[0] = 0x1b;
9509 spec->autocfg.speaker_pins[0] = 0x14;
9510 spec->autocfg.speaker_pins[1] = 0x15;
9511 spec->autocfg.speaker_pins[2] = 0x16;
9512 spec->autocfg.speaker_pins[3] = 0x17;
9513 spec->autocfg.speaker_pins[4] = 0x1a;
Kailang Yange2757d52008-08-26 13:17:46 +02009514}
9515
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009516static void alc883_vaiott_setup(struct hda_codec *codec)
Guido Günther3e1647c52009-06-05 00:47:26 +02009517{
9518 struct alc_spec *spec = codec->spec;
9519
9520 spec->autocfg.hp_pins[0] = 0x15;
9521 spec->autocfg.speaker_pins[0] = 0x14;
9522 spec->autocfg.speaker_pins[1] = 0x17;
Guido Günther3e1647c52009-06-05 00:47:26 +02009523}
9524
Kailang Yange2757d52008-08-26 13:17:46 +02009525static struct hda_verb alc888_asus_m90v_verbs[] = {
9526 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9527 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9528 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9529 /* enable unsolicited event */
9530 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9531 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
9532 { } /* end */
9533};
9534
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009535static void alc883_mode2_setup(struct hda_codec *codec)
Kailang Yange2757d52008-08-26 13:17:46 +02009536{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009537 struct alc_spec *spec = codec->spec;
Kailang Yange2757d52008-08-26 13:17:46 +02009538
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009539 spec->autocfg.hp_pins[0] = 0x1b;
9540 spec->autocfg.speaker_pins[0] = 0x14;
9541 spec->autocfg.speaker_pins[1] = 0x15;
9542 spec->autocfg.speaker_pins[2] = 0x16;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009543 spec->ext_mic.pin = 0x18;
9544 spec->int_mic.pin = 0x19;
9545 spec->ext_mic.mux_idx = 0;
9546 spec->int_mic.mux_idx = 1;
9547 spec->auto_mic = 1;
Kailang Yange2757d52008-08-26 13:17:46 +02009548}
9549
9550static struct hda_verb alc888_asus_eee1601_verbs[] = {
9551 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9552 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9553 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9554 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9555 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9556 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
9557 {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
9558 /* enable unsolicited event */
9559 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9560 { } /* end */
9561};
9562
Kailang Yange2757d52008-08-26 13:17:46 +02009563static void alc883_eee1601_inithook(struct hda_codec *codec)
9564{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009565 struct alc_spec *spec = codec->spec;
9566
9567 spec->autocfg.hp_pins[0] = 0x14;
9568 spec->autocfg.speaker_pins[0] = 0x1b;
9569 alc_automute_pin(codec);
Kailang Yange2757d52008-08-26 13:17:46 +02009570}
9571
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009572static struct hda_verb alc889A_mb31_verbs[] = {
9573 /* Init rear pin (used as headphone output) */
9574 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */
9575 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */
9576 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9577 /* Init line pin (used as output in 4ch and 6ch mode) */
9578 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Connect to CLFE */
9579 /* Init line 2 pin (used as headphone out by default) */
9580 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Use as input */
9581 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */
9582 { } /* end */
9583};
9584
9585/* Mute speakers according to the headphone jack state */
9586static void alc889A_mb31_automute(struct hda_codec *codec)
9587{
9588 unsigned int present;
9589
9590 /* Mute only in 2ch or 4ch mode */
9591 if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0)
9592 == 0x00) {
Wu Fengguang864f92b2009-11-18 12:38:02 +08009593 present = snd_hda_jack_detect(codec, 0x15);
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009594 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9595 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9596 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
9597 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9598 }
9599}
9600
9601static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
9602{
9603 if ((res >> 26) == ALC880_HP_EVENT)
9604 alc889A_mb31_automute(codec);
9605}
9606
Takashi Iwai4953550a2009-06-30 15:28:30 +02009607
Takashi Iwaicb53c622007-08-10 17:21:45 +02009608#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwai4953550a2009-06-30 15:28:30 +02009609#define alc882_loopbacks alc880_loopbacks
Takashi Iwaicb53c622007-08-10 17:21:45 +02009610#endif
9611
Sasha Alexandrdef319f2009-06-16 16:00:15 -04009612/* pcm configuration: identical with ALC880 */
Takashi Iwai4953550a2009-06-30 15:28:30 +02009613#define alc882_pcm_analog_playback alc880_pcm_analog_playback
9614#define alc882_pcm_analog_capture alc880_pcm_analog_capture
9615#define alc882_pcm_digital_playback alc880_pcm_digital_playback
9616#define alc882_pcm_digital_capture alc880_pcm_digital_capture
9617
9618static hda_nid_t alc883_slave_dig_outs[] = {
9619 ALC1200_DIGOUT_NID, 0,
9620};
9621
9622static hda_nid_t alc1200_slave_dig_outs[] = {
9623 ALC883_DIGOUT_NID, 0,
9624};
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009625
9626/*
9627 * configuration and preset
9628 */
Takashi Iwai4953550a2009-06-30 15:28:30 +02009629static const char *alc882_models[ALC882_MODEL_LAST] = {
9630 [ALC882_3ST_DIG] = "3stack-dig",
9631 [ALC882_6ST_DIG] = "6stack-dig",
9632 [ALC882_ARIMA] = "arima",
9633 [ALC882_W2JC] = "w2jc",
9634 [ALC882_TARGA] = "targa",
9635 [ALC882_ASUS_A7J] = "asus-a7j",
9636 [ALC882_ASUS_A7M] = "asus-a7m",
9637 [ALC885_MACPRO] = "macpro",
9638 [ALC885_MB5] = "mb5",
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009639 [ALC885_MACMINI3] = "macmini3",
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08009640 [ALC885_MBA21] = "mba21",
Takashi Iwai4953550a2009-06-30 15:28:30 +02009641 [ALC885_MBP3] = "mbp3",
9642 [ALC885_IMAC24] = "imac24",
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009643 [ALC885_IMAC91] = "imac91",
Takashi Iwai4953550a2009-06-30 15:28:30 +02009644 [ALC883_3ST_2ch_DIG] = "3stack-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009645 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
9646 [ALC883_3ST_6ch] = "3stack-6ch",
Takashi Iwai4953550a2009-06-30 15:28:30 +02009647 [ALC883_6ST_DIG] = "alc883-6stack-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009648 [ALC883_TARGA_DIG] = "targa-dig",
9649 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
David Heidelberger64a8be72009-06-08 16:15:18 +02009650 [ALC883_TARGA_8ch_DIG] = "targa-8ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009651 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02009652 [ALC883_ACER_ASPIRE] = "acer-aspire",
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009653 [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g",
Takashi Iwaib1a91462009-06-21 10:56:44 +02009654 [ALC888_ACER_ASPIRE_6530G] = "acer-aspire-6530g",
Hector Martin3b315d72009-06-02 10:54:19 +02009655 [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g",
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009656 [ALC888_ACER_ASPIRE_7730G] = "acer-aspire-7730g",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009657 [ALC883_MEDION] = "medion",
Kailang Yang272a5272007-05-14 11:00:38 +02009658 [ALC883_MEDION_MD2] = "medion-md2",
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009659 [ALC883_MEDION_WIM2160] = "medion-wim2160",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009660 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009661 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02009662 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
9663 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yange2757d52008-08-26 13:17:46 +02009664 [ALC888_LENOVO_SKY] = "lenovo-sky",
Kailang Yang189609a2007-08-20 11:31:23 +02009665 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009666 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009667 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009668 [ALC883_MITAC] = "mitac",
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309669 [ALC883_CLEVO_M540R] = "clevo-m540r",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009670 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +01009671 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009672 [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
Jiang zhe17bba1b2008-06-04 12:11:07 +02009673 [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009674 [ALC889A_INTEL] = "intel-alc889a",
9675 [ALC889_INTEL] = "intel-x58",
Wu Fengguang3ab90932008-11-17 09:51:09 +01009676 [ALC1200_ASUS_P5Q] = "asus-p5q",
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009677 [ALC889A_MB31] = "mb31",
Guido Günther3e1647c52009-06-05 00:47:26 +02009678 [ALC883_SONY_VAIO_TT] = "sony-vaio-tt",
Takashi Iwai4953550a2009-06-30 15:28:30 +02009679 [ALC882_AUTO] = "auto",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009680};
9681
Takashi Iwai4953550a2009-06-30 15:28:30 +02009682static struct snd_pci_quirk alc882_cfg_tbl[] = {
9683 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
9684
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009685 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
Takashi Iwai69e50282008-11-03 10:07:43 +01009686 SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
Takashi Iwai9b6682f2009-03-23 22:50:52 +01009687 SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009688 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
9689 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
Jaroslav Kysela0b18cb12008-07-28 17:07:07 +02009690 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009691 SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
9692 ALC888_ACER_ASPIRE_4930G),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01009693 SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
Takashi Iwai83dd7402009-11-24 08:57:53 +01009694 ALC888_ACER_ASPIRE_4930G),
Hector Martin3b315d72009-06-02 10:54:19 +02009695 SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
9696 ALC888_ACER_ASPIRE_8930G),
Takashi Iwaie46b0c82009-06-13 10:16:43 +02009697 SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
9698 ALC888_ACER_ASPIRE_8930G),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009699 SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO),
9700 SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01009701 SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
Takashi Iwaidde65352009-06-25 08:25:35 +02009702 ALC888_ACER_ASPIRE_6530G),
Juan Jesus Garcia de Soriacc374c42009-02-23 08:11:59 +01009703 SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
Tony Vroond2fd4b02009-06-21 00:40:10 +01009704 ALC888_ACER_ASPIRE_6530G),
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009705 SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
9706 ALC888_ACER_ASPIRE_7730G),
Takashi Iwai22b530e2009-05-13 11:32:52 +02009707 /* default Acer -- disabled as it causes more problems.
9708 * model=auto should work fine now
9709 */
9710 /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */
Takashi Iwai4953550a2009-06-30 15:28:30 +02009711
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009712 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009713
Tobin Davisfebe3372007-06-12 11:27:46 +02009714 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009715 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
9716 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +01009717 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Chris Bagwell06bf3e12009-01-01 10:32:08 +01009718 SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
Herton Ronaldo Krzesinski7ec30f02009-03-04 14:22:52 -03009719 SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009720
9721 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
9722 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
9723 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Kailang Yanga01c30c2008-10-15 11:14:58 +02009724 SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009725 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
9726 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
9727 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009728 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Mackenzie Morgan44a678d2009-02-10 17:13:43 +01009729 SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
Wu Fengguang3ab90932008-11-17 09:51:09 +01009730 SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
Kailang Yange2757d52008-08-26 13:17:46 +02009731 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009732
9733 SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
Travis Place97ec7102008-05-23 18:31:46 +02009734 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009735 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009736 SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009737 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
9738 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
Kailang Yange2757d52008-08-26 13:17:46 +02009739 SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009740 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009741 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
9742
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009743 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
9744 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
9745 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009746 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
Takashi Iwai2fef62c2009-12-18 08:48:42 +01009747 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC882_AUTO),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009748 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009749 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01009750 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009751 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
9752 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
9753 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
9754 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
9755 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
9756 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009757 SND_PCI_QUIRK(0x1462, 0x42cd, "MSI", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009758 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
9759 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
9760 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Anisse Astierb43f6e52010-03-10 19:17:46 +01009761 SND_PCI_QUIRK(0x1462, 0x4570, "MSI Wind Top AE2220", ALC883_TARGA_DIG),
David Heidelberger64a8be72009-06-08 16:15:18 +02009762 SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009763 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
9764 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02009765 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Takashi Iwaiee095432008-11-25 15:03:38 +01009766 SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +01009767 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01009768 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02009769 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Sasha Alexandrdf01b8a2009-06-16 14:46:17 -04009770 SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG),
Anisse Astierb43f6e52010-03-10 19:17:46 +01009771 SND_PCI_QUIRK(0x1462, 0x7437, "MSI NetOn AP1900", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009772 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009773 SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009774
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009775 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Joerg Schirottked1501ea2010-04-15 08:37:41 +02009776 SND_PCI_QUIRK(0x1558, 0x0571, "Clevo laptop M570U", ALC883_3ST_6ch_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009777 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
9778 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309779 SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R),
Takashi Iwaidea0a502009-02-09 17:14:52 +01009780 SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04009781 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009782 /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009783 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009784 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
Takashi Iwaif67d8172009-02-04 23:30:19 +01009785 ALC883_FUJITSU_PI2515),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009786 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009787 ALC888_FUJITSU_XA3530),
Kailang Yang272a5272007-05-14 11:00:38 +02009788 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02009789 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009790 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
9791 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yange2757d52008-08-26 13:17:46 +02009792 SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
Kailang Yang272a5272007-05-14 11:00:38 +02009793 SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
Takashi Iwai959973b2008-11-05 11:30:56 +01009794 SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01009795 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02009796 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009797
Jiang zhe17bba1b2008-06-04 12:11:07 +02009798 SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
9799 SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009800 SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009801 SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL),
9802 SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL),
9803 SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL),
Daniel T Chen572c0e32010-03-14 23:44:03 -04009804 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC882_6ST_DIG),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009805
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009806 {}
9807};
9808
Takashi Iwai4953550a2009-06-30 15:28:30 +02009809/* codec SSID table for Intel Mac */
9810static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
9811 SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3),
9812 SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3),
9813 SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3),
9814 SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO),
9815 SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24),
9816 SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24),
9817 SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3),
Daniel T Chen26fd74f2010-05-30 09:55:23 -04009818 SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31),
Justin P. Mattockab669962010-06-06 16:09:53 -07009819 SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_ASUS_A7M),
Justin P. Mattockf53dae22010-06-06 16:09:51 -07009820 SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC885_MBP3),
Justin P. Mattock6e129702010-06-06 16:09:49 -07009821 SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC885_MBA21),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009822 SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
9823 SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
9824 SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009825 SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009826 SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5),
Luke Yelavich3bfea982010-06-22 11:04:19 +10009827 SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -05009828 /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2,
9829 * so apparently no perfect solution yet
Takashi Iwai4953550a2009-06-30 15:28:30 +02009830 */
9831 SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -05009832 SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5),
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009833 SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC885_MACMINI3),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009834 {} /* terminator */
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08009835};
9836
Takashi Iwai4953550a2009-06-30 15:28:30 +02009837static struct alc_config_preset alc882_presets[] = {
9838 [ALC882_3ST_DIG] = {
9839 .mixers = { alc882_base_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009840 .init_verbs = { alc882_base_init_verbs,
9841 alc882_adc1_init_verbs },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009842 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9843 .dac_nids = alc882_dac_nids,
9844 .dig_out_nid = ALC882_DIGOUT_NID,
9845 .dig_in_nid = ALC882_DIGIN_NID,
9846 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
9847 .channel_mode = alc882_ch_modes,
9848 .need_dac_fix = 1,
9849 .input_mux = &alc882_capture_source,
9850 },
9851 [ALC882_6ST_DIG] = {
9852 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009853 .init_verbs = { alc882_base_init_verbs,
9854 alc882_adc1_init_verbs },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009855 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9856 .dac_nids = alc882_dac_nids,
9857 .dig_out_nid = ALC882_DIGOUT_NID,
9858 .dig_in_nid = ALC882_DIGIN_NID,
9859 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
9860 .channel_mode = alc882_sixstack_modes,
9861 .input_mux = &alc882_capture_source,
9862 },
9863 [ALC882_ARIMA] = {
9864 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009865 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9866 alc882_eapd_verbs },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009867 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9868 .dac_nids = alc882_dac_nids,
9869 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
9870 .channel_mode = alc882_sixstack_modes,
9871 .input_mux = &alc882_capture_source,
9872 },
9873 [ALC882_W2JC] = {
9874 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009875 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9876 alc882_eapd_verbs, alc880_gpio1_init_verbs },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009877 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9878 .dac_nids = alc882_dac_nids,
9879 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
9880 .channel_mode = alc880_threestack_modes,
9881 .need_dac_fix = 1,
9882 .input_mux = &alc882_capture_source,
9883 .dig_out_nid = ALC882_DIGOUT_NID,
9884 },
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08009885 [ALC885_MBA21] = {
9886 .mixers = { alc885_mba21_mixer },
9887 .init_verbs = { alc885_mba21_init_verbs, alc880_gpio1_init_verbs },
9888 .num_dacs = 2,
9889 .dac_nids = alc882_dac_nids,
9890 .channel_mode = alc885_mba21_ch_modes,
9891 .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
9892 .input_mux = &alc882_capture_source,
9893 .unsol_event = alc_automute_amp_unsol_event,
9894 .setup = alc885_mba21_setup,
9895 .init_hook = alc_automute_amp,
9896 },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009897 [ALC885_MBP3] = {
9898 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
9899 .init_verbs = { alc885_mbp3_init_verbs,
9900 alc880_gpio1_init_verbs },
Takashi Iwaibe0ae922009-08-31 08:27:10 +02009901 .num_dacs = 2,
Takashi Iwai4953550a2009-06-30 15:28:30 +02009902 .dac_nids = alc882_dac_nids,
Takashi Iwaibe0ae922009-08-31 08:27:10 +02009903 .hp_nid = 0x04,
9904 .channel_mode = alc885_mbp_4ch_modes,
9905 .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009906 .input_mux = &alc882_capture_source,
9907 .dig_out_nid = ALC882_DIGOUT_NID,
9908 .dig_in_nid = ALC882_DIGIN_NID,
9909 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009910 .setup = alc885_mbp3_setup,
9911 .init_hook = alc_automute_amp,
Takashi Iwai4953550a2009-06-30 15:28:30 +02009912 },
9913 [ALC885_MB5] = {
9914 .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
9915 .init_verbs = { alc885_mb5_init_verbs,
9916 alc880_gpio1_init_verbs },
9917 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9918 .dac_nids = alc882_dac_nids,
9919 .channel_mode = alc885_mb5_6ch_modes,
9920 .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
9921 .input_mux = &mb5_capture_source,
9922 .dig_out_nid = ALC882_DIGOUT_NID,
9923 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +01009924 .unsol_event = alc_automute_amp_unsol_event,
9925 .setup = alc885_mb5_setup,
9926 .init_hook = alc_automute_amp,
Takashi Iwai4953550a2009-06-30 15:28:30 +02009927 },
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009928 [ALC885_MACMINI3] = {
9929 .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer },
9930 .init_verbs = { alc885_macmini3_init_verbs,
9931 alc880_gpio1_init_verbs },
9932 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9933 .dac_nids = alc882_dac_nids,
9934 .channel_mode = alc885_macmini3_6ch_modes,
9935 .num_channel_mode = ARRAY_SIZE(alc885_macmini3_6ch_modes),
9936 .input_mux = &macmini3_capture_source,
9937 .dig_out_nid = ALC882_DIGOUT_NID,
9938 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +01009939 .unsol_event = alc_automute_amp_unsol_event,
9940 .setup = alc885_macmini3_setup,
9941 .init_hook = alc_automute_amp,
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009942 },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009943 [ALC885_MACPRO] = {
9944 .mixers = { alc882_macpro_mixer },
9945 .init_verbs = { alc882_macpro_init_verbs },
9946 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9947 .dac_nids = alc882_dac_nids,
9948 .dig_out_nid = ALC882_DIGOUT_NID,
9949 .dig_in_nid = ALC882_DIGIN_NID,
9950 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
9951 .channel_mode = alc882_ch_modes,
9952 .input_mux = &alc882_capture_source,
9953 .init_hook = alc885_macpro_init_hook,
9954 },
9955 [ALC885_IMAC24] = {
9956 .mixers = { alc885_imac24_mixer },
9957 .init_verbs = { alc885_imac24_init_verbs },
9958 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9959 .dac_nids = alc882_dac_nids,
9960 .dig_out_nid = ALC882_DIGOUT_NID,
9961 .dig_in_nid = ALC882_DIGIN_NID,
9962 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
9963 .channel_mode = alc882_ch_modes,
9964 .input_mux = &alc882_capture_source,
9965 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009966 .setup = alc885_imac24_setup,
Takashi Iwai4953550a2009-06-30 15:28:30 +02009967 .init_hook = alc885_imac24_init_hook,
9968 },
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009969 [ALC885_IMAC91] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07009970 .mixers = {alc885_imac91_mixer},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009971 .init_verbs = { alc885_imac91_init_verbs,
9972 alc880_gpio1_init_verbs },
9973 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9974 .dac_nids = alc882_dac_nids,
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07009975 .channel_mode = alc885_mba21_ch_modes,
9976 .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
9977 .input_mux = &alc889A_imac91_capture_source,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009978 .dig_out_nid = ALC882_DIGOUT_NID,
9979 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +01009980 .unsol_event = alc_automute_amp_unsol_event,
9981 .setup = alc885_imac91_setup,
9982 .init_hook = alc_automute_amp,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009983 },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009984 [ALC882_TARGA] = {
9985 .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009986 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
Takashi Iwai31909b82009-07-10 12:33:48 +02009987 alc880_gpio3_init_verbs, alc882_targa_verbs},
Takashi Iwai4953550a2009-06-30 15:28:30 +02009988 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9989 .dac_nids = alc882_dac_nids,
9990 .dig_out_nid = ALC882_DIGOUT_NID,
9991 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
9992 .adc_nids = alc882_adc_nids,
9993 .capsrc_nids = alc882_capsrc_nids,
9994 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
9995 .channel_mode = alc882_3ST_6ch_modes,
9996 .need_dac_fix = 1,
9997 .input_mux = &alc882_capture_source,
9998 .unsol_event = alc882_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009999 .setup = alc882_targa_setup,
10000 .init_hook = alc882_targa_automute,
Takashi Iwai4953550a2009-06-30 15:28:30 +020010001 },
10002 [ALC882_ASUS_A7J] = {
10003 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010004 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10005 alc882_asus_a7j_verbs},
Takashi Iwai4953550a2009-06-30 15:28:30 +020010006 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10007 .dac_nids = alc882_dac_nids,
10008 .dig_out_nid = ALC882_DIGOUT_NID,
10009 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
10010 .adc_nids = alc882_adc_nids,
10011 .capsrc_nids = alc882_capsrc_nids,
10012 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
10013 .channel_mode = alc882_3ST_6ch_modes,
10014 .need_dac_fix = 1,
10015 .input_mux = &alc882_capture_source,
10016 },
10017 [ALC882_ASUS_A7M] = {
10018 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010019 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10020 alc882_eapd_verbs, alc880_gpio1_init_verbs,
Takashi Iwai4953550a2009-06-30 15:28:30 +020010021 alc882_asus_a7m_verbs },
10022 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10023 .dac_nids = alc882_dac_nids,
10024 .dig_out_nid = ALC882_DIGOUT_NID,
10025 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
10026 .channel_mode = alc880_threestack_modes,
10027 .need_dac_fix = 1,
10028 .input_mux = &alc882_capture_source,
10029 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010030 [ALC883_3ST_2ch_DIG] = {
10031 .mixers = { alc883_3ST_2ch_mixer },
10032 .init_verbs = { alc883_init_verbs },
10033 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10034 .dac_nids = alc883_dac_nids,
10035 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010036 .dig_in_nid = ALC883_DIGIN_NID,
10037 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10038 .channel_mode = alc883_3ST_2ch_modes,
10039 .input_mux = &alc883_capture_source,
10040 },
10041 [ALC883_3ST_6ch_DIG] = {
10042 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10043 .init_verbs = { alc883_init_verbs },
10044 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10045 .dac_nids = alc883_dac_nids,
10046 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010047 .dig_in_nid = ALC883_DIGIN_NID,
10048 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10049 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020010050 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010051 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010052 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010053 [ALC883_3ST_6ch] = {
10054 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10055 .init_verbs = { alc883_init_verbs },
10056 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10057 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010058 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10059 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020010060 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010061 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010062 },
Jiang zhe17bba1b2008-06-04 12:11:07 +020010063 [ALC883_3ST_6ch_INTEL] = {
10064 .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
10065 .init_verbs = { alc883_init_verbs },
10066 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10067 .dac_nids = alc883_dac_nids,
10068 .dig_out_nid = ALC883_DIGOUT_NID,
10069 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangf3cd3f52009-04-02 19:44:18 +080010070 .slave_dig_outs = alc883_slave_dig_outs,
Jiang zhe17bba1b2008-06-04 12:11:07 +020010071 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
10072 .channel_mode = alc883_3ST_6ch_intel_modes,
10073 .need_dac_fix = 1,
10074 .input_mux = &alc883_3stack_6ch_intel,
10075 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010076 [ALC889A_INTEL] = {
10077 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020010078 .init_verbs = { alc885_init_verbs, alc885_init_input_verbs,
10079 alc_hp15_unsol_verbs },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010080 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10081 .dac_nids = alc883_dac_nids,
10082 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10083 .adc_nids = alc889_adc_nids,
10084 .dig_out_nid = ALC883_DIGOUT_NID,
10085 .dig_in_nid = ALC883_DIGIN_NID,
10086 .slave_dig_outs = alc883_slave_dig_outs,
10087 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
10088 .channel_mode = alc889_8ch_intel_modes,
10089 .capsrc_nids = alc889_capsrc_nids,
10090 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010091 .setup = alc889_automute_setup,
10092 .init_hook = alc_automute_amp,
Wu Fengguang6732bd02009-07-30 09:19:14 +020010093 .unsol_event = alc_automute_amp_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010094 .need_dac_fix = 1,
10095 },
10096 [ALC889_INTEL] = {
10097 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
10098 .init_verbs = { alc885_init_verbs, alc889_init_input_verbs,
Wu Fengguang6732bd02009-07-30 09:19:14 +020010099 alc889_eapd_verbs, alc_hp15_unsol_verbs},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010100 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10101 .dac_nids = alc883_dac_nids,
10102 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10103 .adc_nids = alc889_adc_nids,
10104 .dig_out_nid = ALC883_DIGOUT_NID,
10105 .dig_in_nid = ALC883_DIGIN_NID,
10106 .slave_dig_outs = alc883_slave_dig_outs,
10107 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
10108 .channel_mode = alc889_8ch_intel_modes,
10109 .capsrc_nids = alc889_capsrc_nids,
10110 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010111 .setup = alc889_automute_setup,
Wu Fengguang6732bd02009-07-30 09:19:14 +020010112 .init_hook = alc889_intel_init_hook,
10113 .unsol_event = alc_automute_amp_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010114 .need_dac_fix = 1,
10115 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010116 [ALC883_6ST_DIG] = {
10117 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
10118 .init_verbs = { alc883_init_verbs },
10119 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10120 .dac_nids = alc883_dac_nids,
10121 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010122 .dig_in_nid = ALC883_DIGIN_NID,
10123 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10124 .channel_mode = alc883_sixstack_modes,
10125 .input_mux = &alc883_capture_source,
10126 },
Kailang Yangccc656c2006-10-17 12:32:26 +020010127 [ALC883_TARGA_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010128 .mixers = { alc883_targa_mixer, alc883_chmode_mixer },
David Heidelberger005b1072009-07-09 18:45:46 +020010129 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
10130 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020010131 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10132 .dac_nids = alc883_dac_nids,
10133 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +020010134 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10135 .channel_mode = alc883_3ST_6ch_modes,
10136 .need_dac_fix = 1,
10137 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010138 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010139 .setup = alc882_targa_setup,
10140 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010141 },
10142 [ALC883_TARGA_2ch_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010143 .mixers = { alc883_targa_2ch_mixer},
David Heidelberger005b1072009-07-09 18:45:46 +020010144 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
10145 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020010146 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10147 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010148 .adc_nids = alc883_adc_nids_alt,
10149 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010150 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangccc656c2006-10-17 12:32:26 +020010151 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +020010152 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10153 .channel_mode = alc883_3ST_2ch_modes,
10154 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010155 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010156 .setup = alc882_targa_setup,
10157 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010158 },
David Heidelberger64a8be72009-06-08 16:15:18 +020010159 [ALC883_TARGA_8ch_DIG] = {
Takashi Iwaib99dba32009-09-17 18:23:00 +020010160 .mixers = { alc883_targa_mixer, alc883_targa_8ch_mixer,
10161 alc883_chmode_mixer },
David Heidelberger64a8be72009-06-08 16:15:18 +020010162 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010163 alc883_targa_verbs },
David Heidelberger64a8be72009-06-08 16:15:18 +020010164 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10165 .dac_nids = alc883_dac_nids,
10166 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10167 .adc_nids = alc883_adc_nids_rev,
10168 .capsrc_nids = alc883_capsrc_nids_rev,
10169 .dig_out_nid = ALC883_DIGOUT_NID,
10170 .dig_in_nid = ALC883_DIGIN_NID,
10171 .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes),
10172 .channel_mode = alc883_4ST_8ch_modes,
10173 .need_dac_fix = 1,
10174 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010175 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010176 .setup = alc882_targa_setup,
10177 .init_hook = alc882_targa_automute,
David Heidelberger64a8be72009-06-08 16:15:18 +020010178 },
Vladimir Avdoninbab282b92006-08-22 13:31:58 +020010179 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010180 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b92006-08-22 13:31:58 +020010181 /* On TravelMate laptops, GPIO 0 enables the internal speaker
10182 * and the headphone jack. Turn this on and rely on the
10183 * standard mute methods whenever the user wants to turn
10184 * these outputs off.
10185 */
10186 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
10187 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10188 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b92006-08-22 13:31:58 +020010189 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10190 .channel_mode = alc883_3ST_2ch_modes,
10191 .input_mux = &alc883_capture_source,
10192 },
Tobin Davis2880a862007-08-07 11:50:26 +020010193 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010194 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +020010195 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +020010196 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10197 .dac_nids = alc883_dac_nids,
10198 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +020010199 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10200 .channel_mode = alc883_3ST_2ch_modes,
10201 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010202 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010203 .setup = alc883_acer_aspire_setup,
10204 .init_hook = alc_automute_amp,
Kailang Yangd1a991a2007-08-15 16:21:59 +020010205 },
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010206 [ALC888_ACER_ASPIRE_4930G] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010207 .mixers = { alc888_base_mixer,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010208 alc883_chmode_mixer },
10209 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10210 alc888_acer_aspire_4930g_verbs },
10211 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10212 .dac_nids = alc883_dac_nids,
10213 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10214 .adc_nids = alc883_adc_nids_rev,
10215 .capsrc_nids = alc883_capsrc_nids_rev,
10216 .dig_out_nid = ALC883_DIGOUT_NID,
10217 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10218 .channel_mode = alc883_3ST_6ch_modes,
10219 .need_dac_fix = 1,
Łukasz Wojniłowicz973b8cb2010-01-24 14:12:37 +010010220 .const_channel_count = 6,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010221 .num_mux_defs =
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010222 ARRAY_SIZE(alc888_2_capture_sources),
10223 .input_mux = alc888_2_capture_sources,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010224 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010225 .setup = alc888_acer_aspire_4930g_setup,
10226 .init_hook = alc_automute_amp,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010227 },
Tony Vroond2fd4b02009-06-21 00:40:10 +010010228 [ALC888_ACER_ASPIRE_6530G] = {
10229 .mixers = { alc888_acer_aspire_6530_mixer },
10230 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10231 alc888_acer_aspire_6530g_verbs },
10232 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10233 .dac_nids = alc883_dac_nids,
10234 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10235 .adc_nids = alc883_adc_nids_rev,
10236 .capsrc_nids = alc883_capsrc_nids_rev,
10237 .dig_out_nid = ALC883_DIGOUT_NID,
10238 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10239 .channel_mode = alc883_3ST_2ch_modes,
10240 .num_mux_defs =
10241 ARRAY_SIZE(alc888_2_capture_sources),
10242 .input_mux = alc888_acer_aspire_6530_sources,
10243 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010244 .setup = alc888_acer_aspire_6530g_setup,
10245 .init_hook = alc_automute_amp,
Tony Vroond2fd4b02009-06-21 00:40:10 +010010246 },
Hector Martin3b315d72009-06-02 10:54:19 +020010247 [ALC888_ACER_ASPIRE_8930G] = {
Hector Martin556eea92009-12-20 22:51:23 +010010248 .mixers = { alc889_acer_aspire_8930g_mixer,
Hector Martin3b315d72009-06-02 10:54:19 +020010249 alc883_chmode_mixer },
10250 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
Hector Martin0f86a222009-12-20 22:51:18 +010010251 alc889_acer_aspire_8930g_verbs,
10252 alc889_eapd_verbs},
Hector Martin3b315d72009-06-02 10:54:19 +020010253 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10254 .dac_nids = alc883_dac_nids,
Hector Martin018df412009-06-04 00:13:40 +020010255 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10256 .adc_nids = alc889_adc_nids,
10257 .capsrc_nids = alc889_capsrc_nids,
Hector Martin3b315d72009-06-02 10:54:19 +020010258 .dig_out_nid = ALC883_DIGOUT_NID,
10259 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10260 .channel_mode = alc883_3ST_6ch_modes,
10261 .need_dac_fix = 1,
10262 .const_channel_count = 6,
10263 .num_mux_defs =
Hector Martin018df412009-06-04 00:13:40 +020010264 ARRAY_SIZE(alc889_capture_sources),
10265 .input_mux = alc889_capture_sources,
Hector Martin3b315d72009-06-02 10:54:19 +020010266 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010267 .setup = alc889_acer_aspire_8930g_setup,
10268 .init_hook = alc_automute_amp,
Hector Martinf5de24b2009-12-20 22:51:31 +010010269#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050010270 .power_hook = alc_power_eapd,
Hector Martinf5de24b2009-12-20 22:51:31 +010010271#endif
Hector Martin3b315d72009-06-02 10:54:19 +020010272 },
Denis Kuplyakovfc86f952009-08-25 18:15:59 +020010273 [ALC888_ACER_ASPIRE_7730G] = {
10274 .mixers = { alc883_3ST_6ch_mixer,
10275 alc883_chmode_mixer },
10276 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10277 alc888_acer_aspire_7730G_verbs },
10278 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10279 .dac_nids = alc883_dac_nids,
10280 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10281 .adc_nids = alc883_adc_nids_rev,
10282 .capsrc_nids = alc883_capsrc_nids_rev,
10283 .dig_out_nid = ALC883_DIGOUT_NID,
10284 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10285 .channel_mode = alc883_3ST_6ch_modes,
10286 .need_dac_fix = 1,
10287 .const_channel_count = 6,
10288 .input_mux = &alc883_capture_source,
10289 .unsol_event = alc_automute_amp_unsol_event,
10290 .setup = alc888_acer_aspire_6530g_setup,
10291 .init_hook = alc_automute_amp,
10292 },
Tobin Davisc07584c2006-10-13 12:32:16 +020010293 [ALC883_MEDION] = {
10294 .mixers = { alc883_fivestack_mixer,
10295 alc883_chmode_mixer },
10296 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010297 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +020010298 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10299 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010300 .adc_nids = alc883_adc_nids_alt,
10301 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010302 .capsrc_nids = alc883_capsrc_nids,
Tobin Davisc07584c2006-10-13 12:32:16 +020010303 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10304 .channel_mode = alc883_sixstack_modes,
10305 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010306 },
Kailang Yang272a5272007-05-14 11:00:38 +020010307 [ALC883_MEDION_MD2] = {
10308 .mixers = { alc883_medion_md2_mixer},
10309 .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
10310 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10311 .dac_nids = alc883_dac_nids,
10312 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +020010313 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10314 .channel_mode = alc883_3ST_2ch_modes,
10315 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010316 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010317 .setup = alc883_medion_md2_setup,
10318 .init_hook = alc_automute_amp,
Kailang Yangea1fb292008-08-26 12:58:38 +020010319 },
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +020010320 [ALC883_MEDION_WIM2160] = {
10321 .mixers = { alc883_medion_wim2160_mixer },
10322 .init_verbs = { alc883_init_verbs, alc883_medion_wim2160_verbs },
10323 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10324 .dac_nids = alc883_dac_nids,
10325 .dig_out_nid = ALC883_DIGOUT_NID,
10326 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
10327 .adc_nids = alc883_adc_nids,
10328 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10329 .channel_mode = alc883_3ST_2ch_modes,
10330 .input_mux = &alc883_capture_source,
10331 .unsol_event = alc_automute_amp_unsol_event,
10332 .setup = alc883_medion_wim2160_setup,
10333 .init_hook = alc_automute_amp,
10334 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010335 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010336 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010337 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
10338 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10339 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010340 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10341 .channel_mode = alc883_3ST_2ch_modes,
10342 .input_mux = &alc883_capture_source,
10343 },
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -043010344 [ALC883_CLEVO_M540R] = {
10345 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10346 .init_verbs = { alc883_init_verbs, alc883_clevo_m540r_verbs },
10347 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10348 .dac_nids = alc883_dac_nids,
10349 .dig_out_nid = ALC883_DIGOUT_NID,
10350 .dig_in_nid = ALC883_DIGIN_NID,
10351 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_clevo_modes),
10352 .channel_mode = alc883_3ST_6ch_clevo_modes,
10353 .need_dac_fix = 1,
10354 .input_mux = &alc883_capture_source,
10355 /* This machine has the hardware HP auto-muting, thus
10356 * we need no software mute via unsol event
10357 */
10358 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010359 [ALC883_CLEVO_M720] = {
10360 .mixers = { alc883_clevo_m720_mixer },
10361 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +010010362 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10363 .dac_nids = alc883_dac_nids,
10364 .dig_out_nid = ALC883_DIGOUT_NID,
10365 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10366 .channel_mode = alc883_3ST_2ch_modes,
10367 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010368 .unsol_event = alc883_clevo_m720_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010369 .setup = alc883_clevo_m720_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010370 .init_hook = alc883_clevo_m720_init_hook,
Jiang zhe368c7a92008-03-04 11:20:33 +010010371 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010372 [ALC883_LENOVO_101E_2ch] = {
10373 .mixers = { alc883_lenovo_101e_2ch_mixer},
10374 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
10375 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10376 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010377 .adc_nids = alc883_adc_nids_alt,
10378 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010379 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010380 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10381 .channel_mode = alc883_3ST_2ch_modes,
10382 .input_mux = &alc883_lenovo_101e_capture_source,
10383 .unsol_event = alc883_lenovo_101e_unsol_event,
10384 .init_hook = alc883_lenovo_101e_all_automute,
10385 },
Kailang Yang272a5272007-05-14 11:00:38 +020010386 [ALC883_LENOVO_NB0763] = {
10387 .mixers = { alc883_lenovo_nb0763_mixer },
10388 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
10389 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10390 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020010391 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10392 .channel_mode = alc883_3ST_2ch_modes,
10393 .need_dac_fix = 1,
10394 .input_mux = &alc883_lenovo_nb0763_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010395 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010396 .setup = alc883_medion_md2_setup,
10397 .init_hook = alc_automute_amp,
Kailang Yang272a5272007-05-14 11:00:38 +020010398 },
10399 [ALC888_LENOVO_MS7195_DIG] = {
10400 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10401 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
10402 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10403 .dac_nids = alc883_dac_nids,
10404 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +020010405 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10406 .channel_mode = alc883_3ST_6ch_modes,
10407 .need_dac_fix = 1,
10408 .input_mux = &alc883_capture_source,
10409 .unsol_event = alc883_lenovo_ms7195_unsol_event,
10410 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +020010411 },
10412 [ALC883_HAIER_W66] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010413 .mixers = { alc883_targa_2ch_mixer},
Kailang Yang189609a2007-08-20 11:31:23 +020010414 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
10415 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10416 .dac_nids = alc883_dac_nids,
10417 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +020010418 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10419 .channel_mode = alc883_3ST_2ch_modes,
10420 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010421 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010422 .setup = alc883_haier_w66_setup,
10423 .init_hook = alc_automute_amp,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +010010424 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010425 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +010010426 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010427 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010428 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10429 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010430 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
10431 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010432 .need_dac_fix = 1,
10433 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010434 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010435 .setup = alc888_3st_hp_setup,
10436 .init_hook = alc_automute_amp,
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010437 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010438 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +010010439 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010440 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
10441 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10442 .dac_nids = alc883_dac_nids,
10443 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010444 .dig_in_nid = ALC883_DIGIN_NID,
10445 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10446 .channel_mode = alc883_sixstack_modes,
10447 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010448 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010449 .setup = alc888_6st_dell_setup,
10450 .init_hook = alc_automute_amp,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010451 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010452 [ALC883_MITAC] = {
10453 .mixers = { alc883_mitac_mixer },
10454 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
10455 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10456 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010457 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10458 .channel_mode = alc883_3ST_2ch_modes,
10459 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010460 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010461 .setup = alc883_mitac_setup,
10462 .init_hook = alc_automute_amp,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010463 },
Jiang zhefb97dc62008-03-06 11:07:11 +010010464 [ALC883_FUJITSU_PI2515] = {
10465 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
10466 .init_verbs = { alc883_init_verbs,
10467 alc883_2ch_fujitsu_pi2515_verbs},
10468 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10469 .dac_nids = alc883_dac_nids,
10470 .dig_out_nid = ALC883_DIGOUT_NID,
10471 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10472 .channel_mode = alc883_3ST_2ch_modes,
10473 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010474 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010475 .setup = alc883_2ch_fujitsu_pi2515_setup,
10476 .init_hook = alc_automute_amp,
Jiang zhefb97dc62008-03-06 11:07:11 +010010477 },
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010478 [ALC888_FUJITSU_XA3530] = {
10479 .mixers = { alc888_base_mixer, alc883_chmode_mixer },
10480 .init_verbs = { alc883_init_verbs,
10481 alc888_fujitsu_xa3530_verbs },
10482 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10483 .dac_nids = alc883_dac_nids,
10484 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10485 .adc_nids = alc883_adc_nids_rev,
10486 .capsrc_nids = alc883_capsrc_nids_rev,
10487 .dig_out_nid = ALC883_DIGOUT_NID,
10488 .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes),
10489 .channel_mode = alc888_4ST_8ch_intel_modes,
10490 .num_mux_defs =
10491 ARRAY_SIZE(alc888_2_capture_sources),
10492 .input_mux = alc888_2_capture_sources,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010493 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010494 .setup = alc888_fujitsu_xa3530_setup,
10495 .init_hook = alc_automute_amp,
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010496 },
Kailang Yange2757d52008-08-26 13:17:46 +020010497 [ALC888_LENOVO_SKY] = {
10498 .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
10499 .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
10500 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10501 .dac_nids = alc883_dac_nids,
10502 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yange2757d52008-08-26 13:17:46 +020010503 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10504 .channel_mode = alc883_sixstack_modes,
10505 .need_dac_fix = 1,
10506 .input_mux = &alc883_lenovo_sky_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010507 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010508 .setup = alc888_lenovo_sky_setup,
10509 .init_hook = alc_automute_amp,
Kailang Yange2757d52008-08-26 13:17:46 +020010510 },
10511 [ALC888_ASUS_M90V] = {
10512 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10513 .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
10514 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10515 .dac_nids = alc883_dac_nids,
10516 .dig_out_nid = ALC883_DIGOUT_NID,
10517 .dig_in_nid = ALC883_DIGIN_NID,
10518 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10519 .channel_mode = alc883_3ST_6ch_modes,
10520 .need_dac_fix = 1,
10521 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010522 .unsol_event = alc_sku_unsol_event,
10523 .setup = alc883_mode2_setup,
10524 .init_hook = alc_inithook,
Kailang Yange2757d52008-08-26 13:17:46 +020010525 },
10526 [ALC888_ASUS_EEE1601] = {
10527 .mixers = { alc883_asus_eee1601_mixer },
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010528 .cap_mixer = alc883_asus_eee1601_cap_mixer,
Kailang Yange2757d52008-08-26 13:17:46 +020010529 .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
10530 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10531 .dac_nids = alc883_dac_nids,
10532 .dig_out_nid = ALC883_DIGOUT_NID,
10533 .dig_in_nid = ALC883_DIGIN_NID,
10534 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10535 .channel_mode = alc883_3ST_2ch_modes,
10536 .need_dac_fix = 1,
10537 .input_mux = &alc883_asus_eee1601_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010538 .unsol_event = alc_sku_unsol_event,
Kailang Yange2757d52008-08-26 13:17:46 +020010539 .init_hook = alc883_eee1601_inithook,
10540 },
Wu Fengguang3ab90932008-11-17 09:51:09 +010010541 [ALC1200_ASUS_P5Q] = {
10542 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
10543 .init_verbs = { alc883_init_verbs },
10544 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10545 .dac_nids = alc883_dac_nids,
10546 .dig_out_nid = ALC1200_DIGOUT_NID,
10547 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangb25c9da2009-02-06 15:02:27 +080010548 .slave_dig_outs = alc1200_slave_dig_outs,
Wu Fengguang3ab90932008-11-17 09:51:09 +010010549 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10550 .channel_mode = alc883_sixstack_modes,
10551 .input_mux = &alc883_capture_source,
10552 },
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010553 [ALC889A_MB31] = {
10554 .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer},
10555 .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs,
10556 alc880_gpio1_init_verbs },
10557 .adc_nids = alc883_adc_nids,
10558 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010559 .capsrc_nids = alc883_capsrc_nids,
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010560 .dac_nids = alc883_dac_nids,
10561 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10562 .channel_mode = alc889A_mb31_6ch_modes,
10563 .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes),
10564 .input_mux = &alc889A_mb31_capture_source,
10565 .dig_out_nid = ALC883_DIGOUT_NID,
10566 .unsol_event = alc889A_mb31_unsol_event,
10567 .init_hook = alc889A_mb31_automute,
10568 },
Guido Günther3e1647c52009-06-05 00:47:26 +020010569 [ALC883_SONY_VAIO_TT] = {
10570 .mixers = { alc883_vaiott_mixer },
10571 .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs },
10572 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10573 .dac_nids = alc883_dac_nids,
10574 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10575 .channel_mode = alc883_3ST_2ch_modes,
10576 .input_mux = &alc883_capture_source,
10577 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010578 .setup = alc883_vaiott_setup,
10579 .init_hook = alc_automute_amp,
Guido Günther3e1647c52009-06-05 00:47:26 +020010580 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010581};
10582
10583
10584/*
Takashi Iwai4953550a2009-06-30 15:28:30 +020010585 * Pin config fixes
10586 */
10587enum {
Takashi Iwai954a29c2010-07-30 10:55:44 +020010588 PINFIX_ABIT_AW9D_MAX,
10589 PINFIX_PB_M5210,
Takashi Iwai4953550a2009-06-30 15:28:30 +020010590};
10591
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010592static const struct alc_fixup alc882_fixups[] = {
10593 [PINFIX_ABIT_AW9D_MAX] = {
Takashi Iwai73413b12010-08-30 09:39:57 +020010594 .pins = (const struct alc_pincfg[]) {
10595 { 0x15, 0x01080104 }, /* side */
10596 { 0x16, 0x01011012 }, /* rear */
10597 { 0x17, 0x01016011 }, /* clfe */
10598 { }
10599 }
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010600 },
Takashi Iwai954a29c2010-07-30 10:55:44 +020010601 [PINFIX_PB_M5210] = {
Takashi Iwai73413b12010-08-30 09:39:57 +020010602 .verbs = (const struct hda_verb[]) {
10603 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
10604 {}
10605 }
Takashi Iwai954a29c2010-07-30 10:55:44 +020010606 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020010607};
10608
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010609static struct snd_pci_quirk alc882_fixup_tbl[] = {
Takashi Iwai954a29c2010-07-30 10:55:44 +020010610 SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
Takashi Iwai4953550a2009-06-30 15:28:30 +020010611 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
10612 {}
10613};
10614
10615/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010616 * BIOS auto configuration
10617 */
Takashi Iwai05f5f472009-08-25 13:10:18 +020010618static int alc882_auto_create_input_ctls(struct hda_codec *codec,
10619 const struct auto_pin_cfg *cfg)
10620{
10621 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x23, 0x22);
10622}
10623
Takashi Iwai4953550a2009-06-30 15:28:30 +020010624static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010625 hda_nid_t nid, int pin_type,
Takashi Iwai489008c2010-04-07 09:06:00 +020010626 hda_nid_t dac)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010627{
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010628 int idx;
10629
Takashi Iwai489008c2010-04-07 09:06:00 +020010630 /* set as output */
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010631 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010632
Takashi Iwai489008c2010-04-07 09:06:00 +020010633 if (dac == 0x25)
10634 idx = 4;
10635 else if (dac >= 0x02 && dac <= 0x05)
10636 idx = dac - 2;
10637 else
10638 return;
10639 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010640}
10641
Takashi Iwai4953550a2009-06-30 15:28:30 +020010642static void alc882_auto_init_multi_out(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010643{
10644 struct alc_spec *spec = codec->spec;
10645 int i;
10646
10647 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010648 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020010649 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010650 if (nid)
Takashi Iwai4953550a2009-06-30 15:28:30 +020010651 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai489008c2010-04-07 09:06:00 +020010652 spec->multiout.dac_nids[i]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010653 }
10654}
10655
Takashi Iwai4953550a2009-06-30 15:28:30 +020010656static void alc882_auto_init_hp_out(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010657{
10658 struct alc_spec *spec = codec->spec;
Takashi Iwai489008c2010-04-07 09:06:00 +020010659 hda_nid_t pin, dac;
Takashi Iwai5855fb82010-09-16 18:24:02 +020010660 int i;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010661
Takashi Iwai5855fb82010-09-16 18:24:02 +020010662 for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
10663 pin = spec->autocfg.hp_pins[i];
10664 if (!pin)
10665 break;
Takashi Iwai489008c2010-04-07 09:06:00 +020010666 dac = spec->multiout.hp_nid;
10667 if (!dac)
10668 dac = spec->multiout.dac_nids[0]; /* to front */
10669 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
10670 }
Takashi Iwai5855fb82010-09-16 18:24:02 +020010671 for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
10672 pin = spec->autocfg.speaker_pins[i];
10673 if (!pin)
10674 break;
Takashi Iwai489008c2010-04-07 09:06:00 +020010675 dac = spec->multiout.extra_out_nid[0];
10676 if (!dac)
10677 dac = spec->multiout.dac_nids[0]; /* to front */
10678 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
10679 }
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010680}
10681
Takashi Iwai4953550a2009-06-30 15:28:30 +020010682static void alc882_auto_init_analog_input(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010683{
10684 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010685 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010686 int i;
10687
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010688 for (i = 0; i < cfg->num_inputs; i++) {
10689 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai30ea0982010-09-16 18:47:56 +020010690 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwai4953550a2009-06-30 15:28:30 +020010691 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
10692 snd_hda_codec_write(codec, nid, 0,
10693 AC_VERB_SET_AMP_GAIN_MUTE,
10694 AMP_OUT_MUTE);
10695 }
10696}
10697
10698static void alc882_auto_init_input_src(struct hda_codec *codec)
10699{
10700 struct alc_spec *spec = codec->spec;
10701 int c;
10702
10703 for (c = 0; c < spec->num_adc_nids; c++) {
10704 hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
10705 hda_nid_t nid = spec->capsrc_nids[c];
10706 unsigned int mux_idx;
10707 const struct hda_input_mux *imux;
10708 int conns, mute, idx, item;
10709
10710 conns = snd_hda_get_connections(codec, nid, conn_list,
10711 ARRAY_SIZE(conn_list));
10712 if (conns < 0)
10713 continue;
10714 mux_idx = c >= spec->num_mux_defs ? 0 : c;
10715 imux = &spec->input_mux[mux_idx];
Takashi Iwai53111142010-03-08 12:13:07 +010010716 if (!imux->num_items && mux_idx > 0)
10717 imux = &spec->input_mux[0];
Takashi Iwai4953550a2009-06-30 15:28:30 +020010718 for (idx = 0; idx < conns; idx++) {
10719 /* if the current connection is the selected one,
10720 * unmute it as default - otherwise mute it
10721 */
10722 mute = AMP_IN_MUTE(idx);
10723 for (item = 0; item < imux->num_items; item++) {
10724 if (imux->items[item].index == idx) {
10725 if (spec->cur_mux[c] == item)
10726 mute = AMP_IN_UNMUTE(idx);
10727 break;
10728 }
10729 }
10730 /* check if we have a selector or mixer
10731 * we could check for the widget type instead, but
10732 * just check for Amp-In presence (in case of mixer
10733 * without amp-in there is something wrong, this
10734 * function shouldn't be used or capsrc nid is wrong)
10735 */
10736 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010737 snd_hda_codec_write(codec, nid, 0,
10738 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwai4953550a2009-06-30 15:28:30 +020010739 mute);
10740 else if (mute != AMP_IN_MUTE(idx))
10741 snd_hda_codec_write(codec, nid, 0,
10742 AC_VERB_SET_CONNECT_SEL,
10743 idx);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010744 }
10745 }
10746}
10747
Takashi Iwai4953550a2009-06-30 15:28:30 +020010748/* add mic boosts if needed */
10749static int alc_auto_add_mic_boost(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010750{
10751 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010752 struct auto_pin_cfg *cfg = &spec->autocfg;
10753 int i, err;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010754 hda_nid_t nid;
10755
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010756 for (i = 0; i < cfg->num_inputs; i++) {
Takashi Iwai86e29592010-09-09 14:50:17 +020010757 if (cfg->inputs[i].type > AUTO_PIN_MIC)
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010758 break;
10759 nid = cfg->inputs[i].pin;
10760 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
Takashi Iwai10a20af2010-09-09 16:28:02 +020010761 char label[32];
10762 snprintf(label, sizeof(label), "%s Boost",
10763 hda_get_autocfg_input_label(codec, cfg, i));
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010764 err = add_control(spec, ALC_CTL_WIDGET_VOL, label, 0,
Takashi Iwai4953550a2009-06-30 15:28:30 +020010765 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010766 if (err < 0)
10767 return err;
10768 }
Takashi Iwai4953550a2009-06-30 15:28:30 +020010769 }
10770 return 0;
10771}
10772
10773/* almost identical with ALC880 parser... */
10774static int alc882_parse_auto_config(struct hda_codec *codec)
10775{
10776 struct alc_spec *spec = codec->spec;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010777 static hda_nid_t alc882_ignore[] = { 0x1d, 0 };
Takashi Iwai757899a2010-07-30 10:48:14 +020010778 int err;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010779
Takashi Iwai05f5f472009-08-25 13:10:18 +020010780 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10781 alc882_ignore);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010782 if (err < 0)
10783 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010784 if (!spec->autocfg.line_outs)
10785 return 0; /* can't find valid BIOS pin config */
10786
10787 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
10788 if (err < 0)
10789 return err;
10790 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
10791 if (err < 0)
10792 return err;
Takashi Iwai489008c2010-04-07 09:06:00 +020010793 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
10794 "Headphone");
10795 if (err < 0)
10796 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010797 err = alc880_auto_create_extra_out(spec,
10798 spec->autocfg.speaker_pins[0],
10799 "Speaker");
10800 if (err < 0)
10801 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010802 err = alc882_auto_create_input_ctls(codec, &spec->autocfg);
10803 if (err < 0)
10804 return err;
10805
10806 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10807
Takashi Iwai757899a2010-07-30 10:48:14 +020010808 alc_auto_parse_digital(codec);
Takashi Iwai05f5f472009-08-25 13:10:18 +020010809
10810 if (spec->kctls.list)
10811 add_mixer(spec, spec->kctls.list);
10812
10813 add_verb(spec, alc883_auto_init_verbs);
10814 /* if ADC 0x07 is available, initialize it, too */
10815 if (get_wcaps_type(get_wcaps(codec, 0x07)) == AC_WID_AUD_IN)
10816 add_verb(spec, alc882_adc1_init_verbs);
10817
10818 spec->num_mux_defs = 1;
10819 spec->input_mux = &spec->private_imux[0];
10820
Kailang Yang6227cdc2010-02-25 08:36:52 +010010821 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai776e1842007-08-29 15:07:11 +020010822
10823 err = alc_auto_add_mic_boost(codec);
10824 if (err < 0)
10825 return err;
10826
Takashi Iwai776e1842007-08-29 15:07:11 +020010827 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010828}
10829
10830/* additional initialization for auto-configuration model */
Takashi Iwai4953550a2009-06-30 15:28:30 +020010831static void alc882_auto_init(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010832{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010833 struct alc_spec *spec = codec->spec;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010834 alc882_auto_init_multi_out(codec);
10835 alc882_auto_init_hp_out(codec);
10836 alc882_auto_init_analog_input(codec);
10837 alc882_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020010838 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010839 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020010840 alc_inithook(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010841}
10842
Takashi Iwai4953550a2009-06-30 15:28:30 +020010843static int patch_alc882(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010844{
10845 struct alc_spec *spec;
10846 int err, board_config;
10847
10848 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
10849 if (spec == NULL)
10850 return -ENOMEM;
10851
10852 codec->spec = spec;
10853
Kailang Yangda00c242010-03-19 11:23:45 +010010854 alc_auto_parse_customize_define(codec);
10855
Takashi Iwai4953550a2009-06-30 15:28:30 +020010856 switch (codec->vendor_id) {
10857 case 0x10ec0882:
10858 case 0x10ec0885:
10859 break;
10860 default:
10861 /* ALC883 and variants */
10862 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
10863 break;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010864 }
10865
Takashi Iwai4953550a2009-06-30 15:28:30 +020010866 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
10867 alc882_models,
10868 alc882_cfg_tbl);
10869
10870 if (board_config < 0 || board_config >= ALC882_MODEL_LAST)
10871 board_config = snd_hda_check_board_codec_sid_config(codec,
10872 ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
10873
10874 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020010875 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai4953550a2009-06-30 15:28:30 +020010876 codec->chip_name);
10877 board_config = ALC882_AUTO;
10878 }
10879
Takashi Iwai7fa90e82010-04-12 08:49:00 +020010880 if (board_config == ALC882_AUTO)
10881 alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 1);
Takashi Iwai4953550a2009-06-30 15:28:30 +020010882
10883 if (board_config == ALC882_AUTO) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010884 /* automatic parse from the BIOS config */
Takashi Iwai4953550a2009-06-30 15:28:30 +020010885 err = alc882_parse_auto_config(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010886 if (err < 0) {
10887 alc_free(codec);
10888 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010889 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010890 printk(KERN_INFO
10891 "hda_codec: Cannot set up configuration "
10892 "from BIOS. Using base mode...\n");
Takashi Iwai4953550a2009-06-30 15:28:30 +020010893 board_config = ALC882_3ST_DIG;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010894 }
10895 }
10896
Takashi Iwaidc1eae22010-07-29 15:30:02 +020010897 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020010898 err = snd_hda_attach_beep_device(codec, 0x1);
10899 if (err < 0) {
10900 alc_free(codec);
10901 return err;
10902 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090010903 }
10904
Takashi Iwai4953550a2009-06-30 15:28:30 +020010905 if (board_config != ALC882_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020010906 setup_preset(codec, &alc882_presets[board_config]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010907
Takashi Iwai4953550a2009-06-30 15:28:30 +020010908 spec->stream_analog_playback = &alc882_pcm_analog_playback;
10909 spec->stream_analog_capture = &alc882_pcm_analog_capture;
10910 /* FIXME: setup DAC5 */
10911 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
10912 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
10913
10914 spec->stream_digital_playback = &alc882_pcm_digital_playback;
10915 spec->stream_digital_capture = &alc882_pcm_digital_capture;
10916
Takashi Iwai4953550a2009-06-30 15:28:30 +020010917 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010918 int i, j;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010919 spec->num_adc_nids = 0;
10920 for (i = 0; i < ARRAY_SIZE(alc882_adc_nids); i++) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010921 const struct hda_input_mux *imux = spec->input_mux;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010922 hda_nid_t cap;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010923 hda_nid_t items[16];
Takashi Iwai4953550a2009-06-30 15:28:30 +020010924 hda_nid_t nid = alc882_adc_nids[i];
10925 unsigned int wcap = get_wcaps(codec, nid);
10926 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020010927 wcap = get_wcaps_type(wcap);
Takashi Iwai4953550a2009-06-30 15:28:30 +020010928 if (wcap != AC_WID_AUD_IN)
10929 continue;
10930 spec->private_adc_nids[spec->num_adc_nids] = nid;
10931 err = snd_hda_get_connections(codec, nid, &cap, 1);
10932 if (err < 0)
10933 continue;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010934 err = snd_hda_get_connections(codec, cap, items,
10935 ARRAY_SIZE(items));
10936 if (err < 0)
10937 continue;
10938 for (j = 0; j < imux->num_items; j++)
10939 if (imux->items[j].index >= err)
10940 break;
10941 if (j < imux->num_items)
10942 continue;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010943 spec->private_capsrc_nids[spec->num_adc_nids] = cap;
10944 spec->num_adc_nids++;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020010945 }
Takashi Iwai4953550a2009-06-30 15:28:30 +020010946 spec->adc_nids = spec->private_adc_nids;
10947 spec->capsrc_nids = spec->private_capsrc_nids;
Kailang Yang2f893282008-05-27 12:14:47 +020010948 }
10949
Takashi Iwaib59bdf32009-08-11 09:47:30 +020010950 set_capture_mixer(codec);
Kailang Yangda00c242010-03-19 11:23:45 +010010951
Takashi Iwaidc1eae22010-07-29 15:30:02 +020010952 if (has_cdefine_beep(codec))
Kailang Yangda00c242010-03-19 11:23:45 +010010953 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010954
Takashi Iwai7fa90e82010-04-12 08:49:00 +020010955 if (board_config == ALC882_AUTO)
10956 alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 0);
10957
Takashi Iwai2134ea42008-01-10 16:53:55 +010010958 spec->vmaster_nid = 0x0c;
10959
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010960 codec->patch_ops = alc_patch_ops;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010961 if (board_config == ALC882_AUTO)
10962 spec->init_hook = alc882_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020010963#ifdef CONFIG_SND_HDA_POWER_SAVE
10964 if (!spec->loopback.amplist)
Takashi Iwai4953550a2009-06-30 15:28:30 +020010965 spec->loopback.amplist = alc882_loopbacks;
Takashi Iwaicb53c622007-08-10 17:21:45 +020010966#endif
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010967
10968 return 0;
10969}
10970
Takashi Iwai4953550a2009-06-30 15:28:30 +020010971
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010972/*
Kailang Yangdf694da2005-12-05 19:42:22 +010010973 * ALC262 support
10974 */
10975
10976#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
10977#define ALC262_DIGIN_NID ALC880_DIGIN_NID
10978
10979#define alc262_dac_nids alc260_dac_nids
10980#define alc262_adc_nids alc882_adc_nids
10981#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +010010982#define alc262_capsrc_nids alc882_capsrc_nids
10983#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +010010984
10985#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +010010986#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +010010987
Kailang Yang4e555fe2008-08-26 13:05:55 +020010988static hda_nid_t alc262_dmic_adc_nids[1] = {
10989 /* ADC0 */
10990 0x09
10991};
10992
10993static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
10994
Kailang Yangdf694da2005-12-05 19:42:22 +010010995static struct snd_kcontrol_new alc262_base_mixer[] = {
10996 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10997 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10998 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10999 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11000 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11001 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11002 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11003 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010011004 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011005 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11006 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010011007 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011008 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
11009 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11010 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
11011 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011012 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +010011013};
11014
Takashi Iwaice875f02008-01-28 18:17:43 +010011015/* update HP, line and mono-out pins according to the master switch */
11016static void alc262_hp_master_update(struct hda_codec *codec)
11017{
11018 struct alc_spec *spec = codec->spec;
11019 int val = spec->master_sw;
11020
11021 /* HP & line-out */
11022 snd_hda_codec_write_cache(codec, 0x1b, 0,
11023 AC_VERB_SET_PIN_WIDGET_CONTROL,
11024 val ? PIN_HP : 0);
11025 snd_hda_codec_write_cache(codec, 0x15, 0,
11026 AC_VERB_SET_PIN_WIDGET_CONTROL,
11027 val ? PIN_HP : 0);
11028 /* mono (speaker) depending on the HP jack sense */
11029 val = val && !spec->jack_present;
11030 snd_hda_codec_write_cache(codec, 0x16, 0,
11031 AC_VERB_SET_PIN_WIDGET_CONTROL,
11032 val ? PIN_OUT : 0);
11033}
11034
11035static void alc262_hp_bpc_automute(struct hda_codec *codec)
11036{
11037 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080011038
11039 spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
Takashi Iwaice875f02008-01-28 18:17:43 +010011040 alc262_hp_master_update(codec);
11041}
11042
11043static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
11044{
11045 if ((res >> 26) != ALC880_HP_EVENT)
11046 return;
11047 alc262_hp_bpc_automute(codec);
11048}
11049
11050static void alc262_hp_wildwest_automute(struct hda_codec *codec)
11051{
11052 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080011053
11054 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaice875f02008-01-28 18:17:43 +010011055 alc262_hp_master_update(codec);
11056}
11057
11058static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
11059 unsigned int res)
11060{
11061 if ((res >> 26) != ALC880_HP_EVENT)
11062 return;
11063 alc262_hp_wildwest_automute(codec);
11064}
11065
Takashi Iwaib72519b2009-05-08 14:31:55 +020011066#define alc262_hp_master_sw_get alc260_hp_master_sw_get
Takashi Iwaice875f02008-01-28 18:17:43 +010011067
11068static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
11069 struct snd_ctl_elem_value *ucontrol)
11070{
11071 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11072 struct alc_spec *spec = codec->spec;
11073 int val = !!*ucontrol->value.integer.value;
11074
11075 if (val == spec->master_sw)
11076 return 0;
11077 spec->master_sw = val;
11078 alc262_hp_master_update(codec);
11079 return 1;
11080}
11081
Takashi Iwaib72519b2009-05-08 14:31:55 +020011082#define ALC262_HP_MASTER_SWITCH \
11083 { \
11084 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
11085 .name = "Master Playback Switch", \
11086 .info = snd_ctl_boolean_mono_info, \
11087 .get = alc262_hp_master_sw_get, \
11088 .put = alc262_hp_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011089 }, \
11090 { \
11091 .iface = NID_MAPPING, \
11092 .name = "Master Playback Switch", \
11093 .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \
Takashi Iwaib72519b2009-05-08 14:31:55 +020011094 }
11095
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011096
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011097static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020011098 ALC262_HP_MASTER_SWITCH,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011099 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11100 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11101 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010011102 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
11103 HDA_OUTPUT),
11104 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
11105 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011106 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11107 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010011108 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011109 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11110 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010011111 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011112 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11113 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11114 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11115 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011116 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
11117 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
11118 { } /* end */
11119};
11120
Kailang Yangcd7509a2007-01-26 18:33:17 +010011121static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020011122 ALC262_HP_MASTER_SWITCH,
Kailang Yangcd7509a2007-01-26 18:33:17 +010011123 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11124 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
11125 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11126 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010011127 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
11128 HDA_OUTPUT),
11129 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
11130 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011131 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
11132 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010011133 HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011134 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
11135 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
11136 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11137 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011138 { } /* end */
11139};
11140
11141static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
11142 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11143 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010011144 HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011145 { } /* end */
11146};
11147
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011148/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011149static void alc262_hp_t5735_setup(struct hda_codec *codec)
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011150{
11151 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011152
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011153 spec->autocfg.hp_pins[0] = 0x15;
Takashi Iwaidc99be42010-01-20 08:35:06 +010011154 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011155}
11156
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011157static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010011158 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11159 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011160 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11161 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11162 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11163 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11164 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11165 { } /* end */
11166};
11167
11168static struct hda_verb alc262_hp_t5735_verbs[] = {
11169 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11170 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11171
11172 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11173 { }
11174};
11175
Kailang Yang8c427222008-01-10 13:03:59 +010011176static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +010011177 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11178 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010011179 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
11180 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010011181 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
11182 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
11183 { } /* end */
11184};
11185
11186static struct hda_verb alc262_hp_rp5700_verbs[] = {
11187 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11188 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11189 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11190 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11191 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11192 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11193 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11194 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11195 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
11196 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
11197 {}
11198};
11199
11200static struct hda_input_mux alc262_hp_rp5700_capture_source = {
11201 .num_items = 1,
11202 .items = {
11203 { "Line", 0x1 },
11204 },
11205};
11206
Takashi Iwai42171c12009-05-08 14:11:43 +020011207/* bind hp and internal speaker mute (with plug check) as master switch */
11208static void alc262_hippo_master_update(struct hda_codec *codec)
11209{
11210 struct alc_spec *spec = codec->spec;
11211 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
11212 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
11213 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
11214 unsigned int mute;
11215
11216 /* HP */
11217 mute = spec->master_sw ? 0 : HDA_AMP_MUTE;
11218 snd_hda_codec_amp_stereo(codec, hp_nid, HDA_OUTPUT, 0,
11219 HDA_AMP_MUTE, mute);
11220 /* mute internal speaker per jack sense */
11221 if (spec->jack_present)
11222 mute = HDA_AMP_MUTE;
11223 if (line_nid)
11224 snd_hda_codec_amp_stereo(codec, line_nid, HDA_OUTPUT, 0,
11225 HDA_AMP_MUTE, mute);
11226 if (speaker_nid && speaker_nid != line_nid)
11227 snd_hda_codec_amp_stereo(codec, speaker_nid, HDA_OUTPUT, 0,
11228 HDA_AMP_MUTE, mute);
11229}
11230
11231#define alc262_hippo_master_sw_get alc262_hp_master_sw_get
11232
11233static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol,
11234 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai0724ea22007-08-23 00:31:43 +020011235{
11236 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Takashi Iwai42171c12009-05-08 14:11:43 +020011237 struct alc_spec *spec = codec->spec;
11238 int val = !!*ucontrol->value.integer.value;
Takashi Iwai0724ea22007-08-23 00:31:43 +020011239
Takashi Iwai42171c12009-05-08 14:11:43 +020011240 if (val == spec->master_sw)
11241 return 0;
11242 spec->master_sw = val;
11243 alc262_hippo_master_update(codec);
11244 return 1;
Takashi Iwai0724ea22007-08-23 00:31:43 +020011245}
Takashi Iwai5b319542007-07-26 11:49:22 +020011246
Takashi Iwai42171c12009-05-08 14:11:43 +020011247#define ALC262_HIPPO_MASTER_SWITCH \
11248 { \
11249 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
11250 .name = "Master Playback Switch", \
11251 .info = snd_ctl_boolean_mono_info, \
11252 .get = alc262_hippo_master_sw_get, \
11253 .put = alc262_hippo_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011254 }, \
11255 { \
11256 .iface = NID_MAPPING, \
11257 .name = "Master Playback Switch", \
11258 .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \
11259 (SUBDEV_SPEAKER(0) << 16), \
Takashi Iwai42171c12009-05-08 14:11:43 +020011260 }
11261
11262static struct snd_kcontrol_new alc262_hippo_mixer[] = {
11263 ALC262_HIPPO_MASTER_SWITCH,
11264 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11265 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11266 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11267 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11268 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11269 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11270 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11271 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11272 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11273 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11274 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11275 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11276 { } /* end */
11277};
11278
11279static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
11280 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11281 ALC262_HIPPO_MASTER_SWITCH,
11282 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11283 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11284 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11285 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11286 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11287 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11288 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11289 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11290 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11291 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11292 { } /* end */
11293};
11294
11295/* mute/unmute internal speaker according to the hp jack and mute state */
11296static void alc262_hippo_automute(struct hda_codec *codec)
11297{
11298 struct alc_spec *spec = codec->spec;
11299 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
Takashi Iwai42171c12009-05-08 14:11:43 +020011300
Wu Fengguang864f92b2009-11-18 12:38:02 +080011301 spec->jack_present = snd_hda_jack_detect(codec, hp_nid);
Takashi Iwai42171c12009-05-08 14:11:43 +020011302 alc262_hippo_master_update(codec);
11303}
11304
11305static void alc262_hippo_unsol_event(struct hda_codec *codec, unsigned int res)
11306{
11307 if ((res >> 26) != ALC880_HP_EVENT)
11308 return;
11309 alc262_hippo_automute(codec);
11310}
11311
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011312static void alc262_hippo_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020011313{
11314 struct alc_spec *spec = codec->spec;
11315
11316 spec->autocfg.hp_pins[0] = 0x15;
11317 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai42171c12009-05-08 14:11:43 +020011318}
11319
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011320static void alc262_hippo1_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020011321{
11322 struct alc_spec *spec = codec->spec;
11323
11324 spec->autocfg.hp_pins[0] = 0x1b;
11325 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai42171c12009-05-08 14:11:43 +020011326}
11327
11328
Kailang Yang272a5272007-05-14 11:00:38 +020011329static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +020011330 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011331 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang272a5272007-05-14 11:00:38 +020011332 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11333 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11334 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11335 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11336 { } /* end */
11337};
11338
Kailang Yang83c34212007-07-05 11:43:05 +020011339static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011340 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11341 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang83c34212007-07-05 11:43:05 +020011342 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11343 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11344 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11345 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11346 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11347 { } /* end */
11348};
Kailang Yang272a5272007-05-14 11:00:38 +020011349
Tony Vroonba340e82009-02-02 19:01:30 +000011350static struct snd_kcontrol_new alc262_tyan_mixer[] = {
11351 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11352 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
11353 HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
11354 HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT),
11355 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11356 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11357 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11358 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11359 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11360 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11361 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11362 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11363 { } /* end */
11364};
11365
11366static struct hda_verb alc262_tyan_verbs[] = {
11367 /* Headphone automute */
11368 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11369 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11370 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11371
11372 /* P11 AUX_IN, white 4-pin connector */
11373 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11374 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
11375 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
11376 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
11377
11378 {}
11379};
11380
11381/* unsolicited event for HP jack sensing */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011382static void alc262_tyan_setup(struct hda_codec *codec)
Tony Vroonba340e82009-02-02 19:01:30 +000011383{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011384 struct alc_spec *spec = codec->spec;
Tony Vroonba340e82009-02-02 19:01:30 +000011385
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011386 spec->autocfg.hp_pins[0] = 0x1b;
11387 spec->autocfg.speaker_pins[0] = 0x15;
Tony Vroonba340e82009-02-02 19:01:30 +000011388}
11389
Tony Vroonba340e82009-02-02 19:01:30 +000011390
Kailang Yangdf694da2005-12-05 19:42:22 +010011391#define alc262_capture_mixer alc882_capture_mixer
11392#define alc262_capture_alt_mixer alc882_capture_alt_mixer
11393
11394/*
11395 * generic initialization of ADC, input mixers and output mixers
11396 */
11397static struct hda_verb alc262_init_verbs[] = {
11398 /*
11399 * Unmute ADC0-2 and set the default input to mic-in
11400 */
11401 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11402 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11403 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11404 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11405 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11406 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11407
Takashi Iwaicb53c622007-08-10 17:21:45 +020011408 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010011409 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011410 * Note: PASD motherboards uses the Line In 2 as the input for
11411 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010011412 */
11413 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011414 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11415 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11416 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11417 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11418 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011419
11420 /*
11421 * Set up output mixers (0x0c - 0x0e)
11422 */
11423 /* set vol=0 to output mixers */
11424 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11425 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11426 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11427 /* set up input amps for analog loopback */
11428 /* Amp Indices: DAC = 0, mixer = 1 */
11429 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11430 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11431 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11432 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11433 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11434 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11435
11436 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11437 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11438 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11439 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11440 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11441 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11442
11443 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11444 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11445 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11446 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11447 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Kailang Yangea1fb292008-08-26 12:58:38 +020011448
Kailang Yangdf694da2005-12-05 19:42:22 +010011449 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11450 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Kailang Yangea1fb292008-08-26 12:58:38 +020011451
Kailang Yangdf694da2005-12-05 19:42:22 +010011452 /* FIXME: use matrix-type input source selection */
11453 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
11454 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
11455 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11456 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11457 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11458 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11459 /* Input mixer2 */
11460 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11461 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11462 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11463 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11464 /* Input mixer3 */
11465 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11466 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11467 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011468 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +010011469
11470 { }
11471};
11472
Kailang Yang4e555fe2008-08-26 13:05:55 +020011473static struct hda_verb alc262_eapd_verbs[] = {
11474 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
11475 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
11476 { }
11477};
11478
Kailang Yangccc656c2006-10-17 12:32:26 +020011479static struct hda_verb alc262_hippo1_unsol_verbs[] = {
11480 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11481 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11482 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11483
11484 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11485 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11486 {}
11487};
11488
Kailang Yang272a5272007-05-14 11:00:38 +020011489static struct hda_verb alc262_sony_unsol_verbs[] = {
11490 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11491 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11492 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
11493
11494 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11495 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +090011496 {}
Kailang Yang272a5272007-05-14 11:00:38 +020011497};
11498
Kailang Yang4e555fe2008-08-26 13:05:55 +020011499static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
11500 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11501 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11502 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11503 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11504 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang4e555fe2008-08-26 13:05:55 +020011505 { } /* end */
11506};
11507
11508static struct hda_verb alc262_toshiba_s06_verbs[] = {
11509 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11510 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11511 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11512 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11513 {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
11514 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11515 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11516 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11517 {}
11518};
11519
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011520static void alc262_toshiba_s06_setup(struct hda_codec *codec)
Kailang Yang4e555fe2008-08-26 13:05:55 +020011521{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011522 struct alc_spec *spec = codec->spec;
11523
11524 spec->autocfg.hp_pins[0] = 0x15;
11525 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011526 spec->ext_mic.pin = 0x18;
11527 spec->ext_mic.mux_idx = 0;
11528 spec->int_mic.pin = 0x12;
11529 spec->int_mic.mux_idx = 9;
11530 spec->auto_mic = 1;
Kailang Yang4e555fe2008-08-26 13:05:55 +020011531}
11532
Takashi Iwai834be882006-03-01 14:16:17 +010011533/*
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011534 * nec model
11535 * 0x15 = headphone
11536 * 0x16 = internal speaker
11537 * 0x18 = external mic
11538 */
11539
11540static struct snd_kcontrol_new alc262_nec_mixer[] = {
11541 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
11542 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
11543
11544 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11545 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11546 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11547
11548 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11549 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11550 { } /* end */
11551};
11552
11553static struct hda_verb alc262_nec_verbs[] = {
11554 /* Unmute Speaker */
11555 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11556
11557 /* Headphone */
11558 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11559 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11560
11561 /* External mic to headphone */
11562 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11563 /* External mic to speaker */
11564 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11565 {}
11566};
11567
11568/*
Takashi Iwai834be882006-03-01 14:16:17 +010011569 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +010011570 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
11571 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +010011572 */
11573
11574#define ALC_HP_EVENT 0x37
11575
11576static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
11577 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11578 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +010011579 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11580 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +010011581 {}
11582};
11583
Jiang zhe0e31daf2008-03-20 12:12:39 +010011584static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
11585 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11586 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11587 {}
11588};
11589
Daniel T Chene2595322009-12-19 18:19:02 -050011590static struct hda_verb alc262_lenovo_3000_init_verbs[] = {
11591 /* Front Mic pin: input vref at 50% */
11592 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
11593 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11594 {}
11595};
11596
Takashi Iwai834be882006-03-01 14:16:17 +010011597static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011598 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +010011599 .items = {
11600 { "Mic", 0x0 },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011601 { "Int Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +010011602 { "CD", 0x4 },
11603 },
11604};
11605
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011606static struct hda_input_mux alc262_HP_capture_source = {
11607 .num_items = 5,
11608 .items = {
11609 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +020011610 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011611 { "Line", 0x2 },
11612 { "CD", 0x4 },
11613 { "AUX IN", 0x6 },
11614 },
11615};
11616
zhejiangaccbe492007-08-31 12:36:05 +020011617static struct hda_input_mux alc262_HP_D7000_capture_source = {
11618 .num_items = 4,
11619 .items = {
11620 { "Mic", 0x0 },
11621 { "Front Mic", 0x2 },
11622 { "Line", 0x1 },
11623 { "CD", 0x4 },
11624 },
11625};
11626
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011627/* mute/unmute internal speaker according to the hp jacks and mute state */
Takashi Iwai834be882006-03-01 14:16:17 +010011628static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
11629{
11630 struct alc_spec *spec = codec->spec;
11631 unsigned int mute;
11632
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011633 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011634 spec->jack_present = snd_hda_jack_detect(codec, 0x14) ||
11635 snd_hda_jack_detect(codec, 0x1b);
Takashi Iwai834be882006-03-01 14:16:17 +010011636 spec->sense_updated = 1;
11637 }
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011638 /* unmute internal speaker only if both HPs are unplugged and
11639 * master switch is on
11640 */
11641 if (spec->jack_present)
11642 mute = HDA_AMP_MUTE;
11643 else
Takashi Iwai834be882006-03-01 14:16:17 +010011644 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011645 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
11646 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +010011647}
11648
11649/* unsolicited event for HP jack sensing */
11650static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
11651 unsigned int res)
11652{
11653 if ((res >> 26) != ALC_HP_EVENT)
11654 return;
11655 alc262_fujitsu_automute(codec, 1);
11656}
11657
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011658static void alc262_fujitsu_init_hook(struct hda_codec *codec)
11659{
11660 alc262_fujitsu_automute(codec, 1);
11661}
11662
Takashi Iwai834be882006-03-01 14:16:17 +010011663/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +020011664static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
11665 .ops = &snd_hda_bind_vol,
11666 .values = {
11667 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
11668 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
11669 0
11670 },
11671};
Takashi Iwai834be882006-03-01 14:16:17 +010011672
Jiang zhe0e31daf2008-03-20 12:12:39 +010011673/* mute/unmute internal speaker according to the hp jack and mute state */
11674static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
11675{
11676 struct alc_spec *spec = codec->spec;
11677 unsigned int mute;
11678
11679 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011680 spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
Jiang zhe0e31daf2008-03-20 12:12:39 +010011681 spec->sense_updated = 1;
11682 }
11683 if (spec->jack_present) {
11684 /* mute internal speaker */
11685 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11686 HDA_AMP_MUTE, HDA_AMP_MUTE);
11687 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
11688 HDA_AMP_MUTE, HDA_AMP_MUTE);
11689 } else {
11690 /* unmute internal speaker if necessary */
11691 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
11692 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11693 HDA_AMP_MUTE, mute);
11694 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
11695 HDA_AMP_MUTE, mute);
11696 }
11697}
11698
11699/* unsolicited event for HP jack sensing */
11700static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
11701 unsigned int res)
11702{
11703 if ((res >> 26) != ALC_HP_EVENT)
11704 return;
11705 alc262_lenovo_3000_automute(codec, 1);
11706}
11707
Takashi Iwai8de56b72009-07-24 16:51:47 +020011708static int amp_stereo_mute_update(struct hda_codec *codec, hda_nid_t nid,
11709 int dir, int idx, long *valp)
11710{
11711 int i, change = 0;
11712
11713 for (i = 0; i < 2; i++, valp++)
11714 change |= snd_hda_codec_amp_update(codec, nid, i, dir, idx,
11715 HDA_AMP_MUTE,
11716 *valp ? 0 : HDA_AMP_MUTE);
11717 return change;
11718}
11719
Takashi Iwai834be882006-03-01 14:16:17 +010011720/* bind hp and internal speaker mute (with plug check) */
11721static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
11722 struct snd_ctl_elem_value *ucontrol)
11723{
11724 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11725 long *valp = ucontrol->value.integer.value;
11726 int change;
11727
Takashi Iwai8de56b72009-07-24 16:51:47 +020011728 change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
11729 change |= amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
Takashi Iwai82beb8f2007-08-10 17:09:26 +020011730 if (change)
11731 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +010011732 return change;
11733}
11734
11735static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +020011736 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +010011737 {
11738 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11739 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010011740 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwai834be882006-03-01 14:16:17 +010011741 .info = snd_hda_mixer_amp_switch_info,
11742 .get = snd_hda_mixer_amp_switch_get,
11743 .put = alc262_fujitsu_master_sw_put,
11744 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11745 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011746 {
11747 .iface = NID_MAPPING,
11748 .name = "Master Playback Switch",
11749 .private_value = 0x1b,
11750 },
Takashi Iwai834be882006-03-01 14:16:17 +010011751 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11752 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11753 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11754 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11755 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011756 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
11757 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11758 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010011759 { } /* end */
11760};
11761
Jiang zhe0e31daf2008-03-20 12:12:39 +010011762/* bind hp and internal speaker mute (with plug check) */
11763static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
11764 struct snd_ctl_elem_value *ucontrol)
11765{
11766 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11767 long *valp = ucontrol->value.integer.value;
11768 int change;
11769
Takashi Iwai8de56b72009-07-24 16:51:47 +020011770 change = amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
Jiang zhe0e31daf2008-03-20 12:12:39 +010011771 if (change)
11772 alc262_lenovo_3000_automute(codec, 0);
11773 return change;
11774}
11775
11776static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
11777 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
11778 {
11779 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11780 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010011781 .subdevice = HDA_SUBDEV_AMP_FLAG,
Jiang zhe0e31daf2008-03-20 12:12:39 +010011782 .info = snd_hda_mixer_amp_switch_info,
11783 .get = snd_hda_mixer_amp_switch_get,
11784 .put = alc262_lenovo_3000_master_sw_put,
11785 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
11786 },
11787 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11788 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11789 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11790 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11791 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11792 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
11793 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11794 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
11795 { } /* end */
11796};
11797
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011798static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
11799 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai42171c12009-05-08 14:11:43 +020011800 ALC262_HIPPO_MASTER_SWITCH,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011801 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11802 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11803 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11804 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11805 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11806 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11807 { } /* end */
11808};
11809
Takashi Iwai304dcaa2006-07-25 14:51:16 +020011810/* additional init verbs for Benq laptops */
11811static struct hda_verb alc262_EAPD_verbs[] = {
11812 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
11813 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
11814 {}
11815};
11816
Kailang Yang83c34212007-07-05 11:43:05 +020011817static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
11818 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11819 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11820
11821 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
11822 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
11823 {}
11824};
11825
Tobin Davisf651b502007-10-26 12:40:47 +020011826/* Samsung Q1 Ultra Vista model setup */
11827static struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011828 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11829 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020011830 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11831 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11832 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011833 HDA_CODEC_VOLUME("Headphone Mic Boost", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020011834 { } /* end */
11835};
11836
11837static struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011838 /* output mixer */
11839 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11840 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11841 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11842 /* speaker */
11843 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11844 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11845 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11846 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11847 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +020011848 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011849 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11850 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11851 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11852 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11853 /* internal mic */
11854 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11855 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11856 /* ADC, choose mic */
11857 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11858 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11859 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11860 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11861 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11862 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11863 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
11864 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
11865 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
11866 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +020011867 {}
11868};
11869
Tobin Davisf651b502007-10-26 12:40:47 +020011870/* mute/unmute internal speaker according to the hp jack and mute state */
11871static void alc262_ultra_automute(struct hda_codec *codec)
11872{
11873 struct alc_spec *spec = codec->spec;
11874 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +020011875
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011876 mute = 0;
11877 /* auto-mute only when HP is used as HP */
11878 if (!spec->cur_mux[0]) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011879 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011880 if (spec->jack_present)
11881 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +020011882 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011883 /* mute/unmute internal speaker */
11884 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11885 HDA_AMP_MUTE, mute);
11886 /* mute/unmute HP */
11887 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
11888 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +020011889}
11890
11891/* unsolicited event for HP jack sensing */
11892static void alc262_ultra_unsol_event(struct hda_codec *codec,
11893 unsigned int res)
11894{
11895 if ((res >> 26) != ALC880_HP_EVENT)
11896 return;
11897 alc262_ultra_automute(codec);
11898}
11899
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011900static struct hda_input_mux alc262_ultra_capture_source = {
11901 .num_items = 2,
11902 .items = {
11903 { "Mic", 0x1 },
11904 { "Headphone", 0x7 },
11905 },
11906};
11907
11908static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
11909 struct snd_ctl_elem_value *ucontrol)
11910{
11911 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11912 struct alc_spec *spec = codec->spec;
11913 int ret;
11914
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011915 ret = alc_mux_enum_put(kcontrol, ucontrol);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011916 if (!ret)
11917 return 0;
11918 /* reprogram the HP pin as mic or HP according to the input source */
11919 snd_hda_codec_write_cache(codec, 0x15, 0,
11920 AC_VERB_SET_PIN_WIDGET_CONTROL,
11921 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
11922 alc262_ultra_automute(codec); /* mute/unmute HP */
11923 return ret;
11924}
11925
11926static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
11927 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
11928 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
11929 {
11930 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11931 .name = "Capture Source",
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011932 .info = alc_mux_enum_info,
11933 .get = alc_mux_enum_get,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011934 .put = alc262_ultra_mux_enum_put,
11935 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011936 {
11937 .iface = NID_MAPPING,
11938 .name = "Capture Source",
11939 .private_value = 0x15,
11940 },
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011941 { } /* end */
11942};
11943
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011944/* We use two mixers depending on the output pin; 0x16 is a mono output
11945 * and thus it's bound with a different mixer.
11946 * This function returns which mixer amp should be used.
11947 */
11948static int alc262_check_volbit(hda_nid_t nid)
11949{
11950 if (!nid)
11951 return 0;
11952 else if (nid == 0x16)
11953 return 2;
11954 else
11955 return 1;
11956}
11957
11958static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai033688a2010-09-08 15:47:09 +020011959 const char *pfx, int *vbits, int idx)
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011960{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011961 unsigned long val;
11962 int vbit;
11963
11964 vbit = alc262_check_volbit(nid);
11965 if (!vbit)
11966 return 0;
11967 if (*vbits & vbit) /* a volume control for this mixer already there */
11968 return 0;
11969 *vbits |= vbit;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011970 if (vbit == 2)
11971 val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT);
11972 else
11973 val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT);
Takashi Iwai033688a2010-09-08 15:47:09 +020011974 return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011975}
11976
11977static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai033688a2010-09-08 15:47:09 +020011978 const char *pfx, int idx)
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011979{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011980 unsigned long val;
11981
11982 if (!nid)
11983 return 0;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011984 if (nid == 0x16)
11985 val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
11986 else
11987 val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
Takashi Iwai033688a2010-09-08 15:47:09 +020011988 return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011989}
11990
Kailang Yangdf694da2005-12-05 19:42:22 +010011991/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011992static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
11993 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010011994{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011995 const char *pfx;
11996 int vbits;
Takashi Iwai033688a2010-09-08 15:47:09 +020011997 int i, err;
Kailang Yangdf694da2005-12-05 19:42:22 +010011998
11999 spec->multiout.num_dacs = 1; /* only use one dac */
12000 spec->multiout.dac_nids = spec->private_dac_nids;
12001 spec->multiout.dac_nids[0] = 2;
12002
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012003 if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
12004 pfx = "Master";
12005 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
12006 pfx = "Speaker";
Takashi Iwai033688a2010-09-08 15:47:09 +020012007 else if (cfg->line_out_type == AUTO_PIN_HP_OUT)
12008 pfx = "Headphone";
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012009 else
12010 pfx = "Front";
Takashi Iwai033688a2010-09-08 15:47:09 +020012011 for (i = 0; i < 2; i++) {
12012 err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[i], pfx, i);
12013 if (err < 0)
12014 return err;
12015 if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
12016 err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[i],
12017 "Speaker", i);
12018 if (err < 0)
12019 return err;
12020 }
12021 if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
12022 err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[i],
12023 "Headphone", i);
12024 if (err < 0)
12025 return err;
12026 }
12027 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012028
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012029 vbits = alc262_check_volbit(cfg->line_out_pins[0]) |
12030 alc262_check_volbit(cfg->speaker_pins[0]) |
12031 alc262_check_volbit(cfg->hp_pins[0]);
12032 if (vbits == 1 || vbits == 2)
12033 pfx = "Master"; /* only one mixer is used */
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012034 vbits = 0;
Takashi Iwai033688a2010-09-08 15:47:09 +020012035 for (i = 0; i < 2; i++) {
12036 err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[i], pfx,
12037 &vbits, i);
12038 if (err < 0)
12039 return err;
12040 if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
12041 err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[i],
12042 "Speaker", &vbits, i);
12043 if (err < 0)
12044 return err;
12045 }
12046 if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
12047 err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[i],
12048 "Headphone", &vbits, i);
12049 if (err < 0)
12050 return err;
12051 }
12052 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012053 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +010012054}
12055
Takashi Iwai05f5f472009-08-25 13:10:18 +020012056#define alc262_auto_create_input_ctls \
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +010012057 alc882_auto_create_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +010012058
12059/*
12060 * generic initialization of ADC, input mixers and output mixers
12061 */
12062static struct hda_verb alc262_volume_init_verbs[] = {
12063 /*
12064 * Unmute ADC0-2 and set the default input to mic-in
12065 */
12066 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
12067 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12068 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12069 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12070 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12071 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12072
Takashi Iwaicb53c622007-08-10 17:21:45 +020012073 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010012074 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012075 * Note: PASD motherboards uses the Line In 2 as the input for
12076 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010012077 */
12078 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012079 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12080 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12081 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12082 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12083 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012084
12085 /*
12086 * Set up output mixers (0x0c - 0x0f)
12087 */
12088 /* set vol=0 to output mixers */
12089 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12090 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12091 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yangea1fb292008-08-26 12:58:38 +020012092
Kailang Yangdf694da2005-12-05 19:42:22 +010012093 /* set up input amps for analog loopback */
12094 /* Amp Indices: DAC = 0, mixer = 1 */
12095 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12096 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12097 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12098 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12099 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12100 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12101
12102 /* FIXME: use matrix-type input source selection */
12103 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
12104 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
12105 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12106 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12107 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12108 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12109 /* Input mixer2 */
12110 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12111 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12112 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12113 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12114 /* Input mixer3 */
12115 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12116 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12117 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12118 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12119
12120 { }
12121};
12122
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012123static struct hda_verb alc262_HP_BPC_init_verbs[] = {
12124 /*
12125 * Unmute ADC0-2 and set the default input to mic-in
12126 */
12127 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
12128 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12129 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12130 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12131 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12132 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12133
Takashi Iwaicb53c622007-08-10 17:21:45 +020012134 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012135 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012136 * Note: PASD motherboards uses the Line In 2 as the input for
12137 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012138 */
12139 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012140 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12141 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12142 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12143 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12144 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12145 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12146 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012147
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012148 /*
12149 * Set up output mixers (0x0c - 0x0e)
12150 */
12151 /* set vol=0 to output mixers */
12152 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12153 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12154 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12155
12156 /* set up input amps for analog loopback */
12157 /* Amp Indices: DAC = 0, mixer = 1 */
12158 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12159 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12160 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12161 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12162 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12163 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12164
Takashi Iwaice875f02008-01-28 18:17:43 +010012165 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012166 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12167 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12168
12169 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12170 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12171
12172 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12173 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12174
12175 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12176 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12177 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12178 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12179 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12180
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012181 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012182 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12183 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012184 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012185 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12186 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12187
12188
12189 /* FIXME: use matrix-type input source selection */
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012190 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */
12191 /* Input mixer1: only unmute Mic */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012192 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012193 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12194 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12195 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12196 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12197 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12198 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12199 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12200 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012201 /* Input mixer2 */
12202 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012203 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12204 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12205 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12206 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12207 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12208 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12209 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12210 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012211 /* Input mixer3 */
12212 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012213 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12214 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12215 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12216 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12217 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12218 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12219 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12220 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012221
Takashi Iwaice875f02008-01-28 18:17:43 +010012222 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12223
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012224 { }
12225};
12226
Kailang Yangcd7509a2007-01-26 18:33:17 +010012227static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
12228 /*
12229 * Unmute ADC0-2 and set the default input to mic-in
12230 */
12231 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
12232 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12233 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12234 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12235 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12236 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12237
Takashi Iwaicb53c622007-08-10 17:21:45 +020012238 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +010012239 * mixer widget
12240 * Note: PASD motherboards uses the Line In 2 as the input for front
12241 * panel mic (mic 2)
12242 */
12243 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012244 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12245 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12246 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12247 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12248 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12249 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12250 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
12251 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +010012252 /*
12253 * Set up output mixers (0x0c - 0x0e)
12254 */
12255 /* set vol=0 to output mixers */
12256 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12257 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12258 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12259
12260 /* set up input amps for analog loopback */
12261 /* Amp Indices: DAC = 0, mixer = 1 */
12262 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12263 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12264 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12265 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12266 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12267 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12268
12269
12270 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
12271 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
12272 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
12273 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
12274 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
12275 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
12276 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
12277
12278 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12279 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12280
12281 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12282 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12283
12284 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
12285 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12286 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12287 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
12288 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12289 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12290
12291 /* FIXME: use matrix-type input source selection */
12292 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
12293 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
12294 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
12295 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
12296 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
12297 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
12298 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
12299 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12300 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
12301 /* Input mixer2 */
12302 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12303 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
12304 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
12305 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
12306 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
12307 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12308 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
12309 /* Input mixer3 */
12310 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12311 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
12312 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
12313 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
12314 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
12315 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12316 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
12317
Takashi Iwaice875f02008-01-28 18:17:43 +010012318 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12319
Kailang Yangcd7509a2007-01-26 18:33:17 +010012320 { }
12321};
12322
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012323static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
12324
12325 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */
12326 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12327 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
12328
12329 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */
12330 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
12331 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
12332 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
12333
12334 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */
12335 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12336 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12337 {}
12338};
12339
Takashi Iwai18675e42010-09-08 15:55:44 +020012340/*
12341 * Pin config fixes
12342 */
12343enum {
12344 PINFIX_FSC_H270,
12345};
12346
12347static const struct alc_fixup alc262_fixups[] = {
12348 [PINFIX_FSC_H270] = {
12349 .pins = (const struct alc_pincfg[]) {
12350 { 0x14, 0x99130110 }, /* speaker */
12351 { 0x15, 0x0221142f }, /* front HP */
12352 { 0x1b, 0x0121141f }, /* rear HP */
12353 { }
12354 }
12355 },
12356 [PINFIX_PB_M5210] = {
12357 .verbs = (const struct hda_verb[]) {
12358 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
12359 {}
12360 }
12361 },
12362};
12363
12364static struct snd_pci_quirk alc262_fixup_tbl[] = {
12365 SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270),
12366 {}
12367};
12368
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012369
Takashi Iwaicb53c622007-08-10 17:21:45 +020012370#ifdef CONFIG_SND_HDA_POWER_SAVE
12371#define alc262_loopbacks alc880_loopbacks
12372#endif
12373
Sasha Alexandrdef319f2009-06-16 16:00:15 -040012374/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012375#define alc262_pcm_analog_playback alc880_pcm_analog_playback
12376#define alc262_pcm_analog_capture alc880_pcm_analog_capture
12377#define alc262_pcm_digital_playback alc880_pcm_digital_playback
12378#define alc262_pcm_digital_capture alc880_pcm_digital_capture
12379
12380/*
12381 * BIOS auto configuration
12382 */
12383static int alc262_parse_auto_config(struct hda_codec *codec)
12384{
12385 struct alc_spec *spec = codec->spec;
12386 int err;
12387 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
12388
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012389 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12390 alc262_ignore);
12391 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012392 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012393 if (!spec->autocfg.line_outs) {
Takashi Iwai0852d7a2009-02-11 11:35:15 +010012394 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012395 spec->multiout.max_channels = 2;
12396 spec->no_analog = 1;
12397 goto dig_only;
12398 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012399 return 0; /* can't find valid BIOS pin config */
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012400 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012401 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
12402 if (err < 0)
12403 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020012404 err = alc262_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012405 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012406 return err;
12407
12408 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12409
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012410 dig_only:
Takashi Iwai757899a2010-07-30 10:48:14 +020012411 alc_auto_parse_digital(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012412
Takashi Iwai603c4012008-07-30 15:01:44 +020012413 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012414 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010012415
Takashi Iwaid88897e2008-10-31 15:01:37 +010012416 add_verb(spec, alc262_volume_init_verbs);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020012417 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020012418 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010012419
Takashi Iwai776e1842007-08-29 15:07:11 +020012420 err = alc_auto_add_mic_boost(codec);
12421 if (err < 0)
12422 return err;
12423
Kailang Yang6227cdc2010-02-25 08:36:52 +010012424 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020012425
Kailang Yangdf694da2005-12-05 19:42:22 +010012426 return 1;
12427}
12428
12429#define alc262_auto_init_multi_out alc882_auto_init_multi_out
12430#define alc262_auto_init_hp_out alc882_auto_init_hp_out
12431#define alc262_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaif511b012008-08-15 16:46:42 +020012432#define alc262_auto_init_input_src alc882_auto_init_input_src
Kailang Yangdf694da2005-12-05 19:42:22 +010012433
12434
12435/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012436static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010012437{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012438 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010012439 alc262_auto_init_multi_out(codec);
12440 alc262_auto_init_hp_out(codec);
12441 alc262_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020012442 alc262_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020012443 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012444 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020012445 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012446}
12447
12448/*
12449 * configuration and preset
12450 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012451static const char *alc262_models[ALC262_MODEL_LAST] = {
12452 [ALC262_BASIC] = "basic",
12453 [ALC262_HIPPO] = "hippo",
12454 [ALC262_HIPPO_1] = "hippo_1",
12455 [ALC262_FUJITSU] = "fujitsu",
12456 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +010012457 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +010012458 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +010012459 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012460 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +020012461 [ALC262_BENQ_T31] = "benq-t31",
12462 [ALC262_SONY_ASSAMD] = "sony-assamd",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020012463 [ALC262_TOSHIBA_S06] = "toshiba-s06",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012464 [ALC262_TOSHIBA_RX1] = "toshiba-rx1",
Tobin Davisf651b502007-10-26 12:40:47 +020012465 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +010012466 [ALC262_LENOVO_3000] = "lenovo-3000",
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012467 [ALC262_NEC] = "nec",
Tony Vroonba340e82009-02-02 19:01:30 +000012468 [ALC262_TYAN] = "tyan",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012469 [ALC262_AUTO] = "auto",
12470};
12471
12472static struct snd_pci_quirk alc262_cfg_tbl[] = {
12473 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012474 SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
Takashi Iwaidea0a502009-02-09 17:14:52 +010012475 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
12476 ALC262_HP_BPC),
12477 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series",
12478 ALC262_HP_BPC),
Takashi Iwai53eff7e2009-02-27 17:49:44 +010012479 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
12480 ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012481 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012482 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012483 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012484 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012485 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012486 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012487 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012488 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012489 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
12490 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
12491 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012492 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
12493 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +010012494 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012495 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012496 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012497 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaibd6afe32009-03-04 11:30:25 +010012498 SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */
Takashi Iwai376b5082009-06-22 11:03:13 +020012499 SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06),
Daniel T Chen95491d92009-11-08 19:03:55 -050012500 SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO),
Takashi Iwai12929ba2009-11-17 15:58:35 +010012501 SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO),
Takashi Iwaic5b51652009-11-17 16:01:58 +010012502#if 0 /* disable the quirk since model=auto works better in recent versions */
Takashi Iwaif872a912009-02-26 00:57:01 +010012503 SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
12504 ALC262_SONY_ASSAMD),
Takashi Iwaic5b51652009-11-17 16:01:58 +010012505#endif
Akio Idehara36ca6e12008-06-09 22:57:40 +090012506 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012507 ALC262_TOSHIBA_RX1),
Kailang Yang80ffe862008-10-15 11:23:27 +020012508 SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012509 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +010012510 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Tony Vroonba340e82009-02-02 19:01:30 +000012511 SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
Takashi Iwaidea0a502009-02-09 17:14:52 +010012512 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1",
12513 ALC262_ULTRA),
Luke Yelavich3e420e72008-12-16 12:37:47 +110012514 SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
Jiang zhe0e31daf2008-03-20 12:12:39 +010012515 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012516 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +020012517 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012518 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +010012519 {}
12520};
12521
12522static struct alc_config_preset alc262_presets[] = {
12523 [ALC262_BASIC] = {
12524 .mixers = { alc262_base_mixer },
12525 .init_verbs = { alc262_init_verbs },
12526 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12527 .dac_nids = alc262_dac_nids,
12528 .hp_nid = 0x03,
12529 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12530 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +010012531 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +010012532 },
Kailang Yangccc656c2006-10-17 12:32:26 +020012533 [ALC262_HIPPO] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020012534 .mixers = { alc262_hippo_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020012535 .init_verbs = { alc262_init_verbs, alc_hp15_unsol_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020012536 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12537 .dac_nids = alc262_dac_nids,
12538 .hp_nid = 0x03,
12539 .dig_out_nid = ALC262_DIGOUT_NID,
12540 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12541 .channel_mode = alc262_modes,
12542 .input_mux = &alc262_capture_source,
12543 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012544 .setup = alc262_hippo_setup,
12545 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020012546 },
12547 [ALC262_HIPPO_1] = {
12548 .mixers = { alc262_hippo1_mixer },
12549 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
12550 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12551 .dac_nids = alc262_dac_nids,
12552 .hp_nid = 0x02,
12553 .dig_out_nid = ALC262_DIGOUT_NID,
12554 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12555 .channel_mode = alc262_modes,
12556 .input_mux = &alc262_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020012557 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012558 .setup = alc262_hippo1_setup,
12559 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020012560 },
Takashi Iwai834be882006-03-01 14:16:17 +010012561 [ALC262_FUJITSU] = {
12562 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020012563 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
12564 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +010012565 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12566 .dac_nids = alc262_dac_nids,
12567 .hp_nid = 0x03,
12568 .dig_out_nid = ALC262_DIGOUT_NID,
12569 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12570 .channel_mode = alc262_modes,
12571 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012572 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwaiebc7a402008-05-20 09:23:05 +020012573 .init_hook = alc262_fujitsu_init_hook,
Takashi Iwai834be882006-03-01 14:16:17 +010012574 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012575 [ALC262_HP_BPC] = {
12576 .mixers = { alc262_HP_BPC_mixer },
12577 .init_verbs = { alc262_HP_BPC_init_verbs },
12578 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12579 .dac_nids = alc262_dac_nids,
12580 .hp_nid = 0x03,
12581 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12582 .channel_mode = alc262_modes,
12583 .input_mux = &alc262_HP_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010012584 .unsol_event = alc262_hp_bpc_unsol_event,
12585 .init_hook = alc262_hp_bpc_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012586 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010012587 [ALC262_HP_BPC_D7000_WF] = {
12588 .mixers = { alc262_HP_BPC_WildWest_mixer },
12589 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
12590 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12591 .dac_nids = alc262_dac_nids,
12592 .hp_nid = 0x03,
12593 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12594 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020012595 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010012596 .unsol_event = alc262_hp_wildwest_unsol_event,
12597 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012598 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010012599 [ALC262_HP_BPC_D7000_WL] = {
12600 .mixers = { alc262_HP_BPC_WildWest_mixer,
12601 alc262_HP_BPC_WildWest_option_mixer },
12602 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
12603 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12604 .dac_nids = alc262_dac_nids,
12605 .hp_nid = 0x03,
12606 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12607 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020012608 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010012609 .unsol_event = alc262_hp_wildwest_unsol_event,
12610 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012611 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012612 [ALC262_HP_TC_T5735] = {
12613 .mixers = { alc262_hp_t5735_mixer },
12614 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
12615 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12616 .dac_nids = alc262_dac_nids,
12617 .hp_nid = 0x03,
12618 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12619 .channel_mode = alc262_modes,
12620 .input_mux = &alc262_capture_source,
Takashi Iwaidc99be42010-01-20 08:35:06 +010012621 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012622 .setup = alc262_hp_t5735_setup,
Takashi Iwaidc99be42010-01-20 08:35:06 +010012623 .init_hook = alc_inithook,
Kailang Yang8c427222008-01-10 13:03:59 +010012624 },
12625 [ALC262_HP_RP5700] = {
12626 .mixers = { alc262_hp_rp5700_mixer },
12627 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
12628 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12629 .dac_nids = alc262_dac_nids,
12630 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12631 .channel_mode = alc262_modes,
12632 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012633 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +020012634 [ALC262_BENQ_ED8] = {
12635 .mixers = { alc262_base_mixer },
12636 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
12637 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12638 .dac_nids = alc262_dac_nids,
12639 .hp_nid = 0x03,
12640 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12641 .channel_mode = alc262_modes,
12642 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012643 },
Kailang Yang272a5272007-05-14 11:00:38 +020012644 [ALC262_SONY_ASSAMD] = {
12645 .mixers = { alc262_sony_mixer },
12646 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
12647 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12648 .dac_nids = alc262_dac_nids,
12649 .hp_nid = 0x02,
12650 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12651 .channel_mode = alc262_modes,
12652 .input_mux = &alc262_capture_source,
12653 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012654 .setup = alc262_hippo_setup,
12655 .init_hook = alc262_hippo_automute,
Kailang Yang83c34212007-07-05 11:43:05 +020012656 },
12657 [ALC262_BENQ_T31] = {
12658 .mixers = { alc262_benq_t31_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020012659 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs,
12660 alc_hp15_unsol_verbs },
Kailang Yang83c34212007-07-05 11:43:05 +020012661 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12662 .dac_nids = alc262_dac_nids,
12663 .hp_nid = 0x03,
12664 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12665 .channel_mode = alc262_modes,
12666 .input_mux = &alc262_capture_source,
12667 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012668 .setup = alc262_hippo_setup,
12669 .init_hook = alc262_hippo_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020012670 },
Tobin Davisf651b502007-10-26 12:40:47 +020012671 [ALC262_ULTRA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012672 .mixers = { alc262_ultra_mixer },
12673 .cap_mixer = alc262_ultra_capture_mixer,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012674 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +020012675 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12676 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +020012677 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12678 .channel_mode = alc262_modes,
12679 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012680 .adc_nids = alc262_adc_nids, /* ADC0 */
12681 .capsrc_nids = alc262_capsrc_nids,
12682 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +020012683 .unsol_event = alc262_ultra_unsol_event,
12684 .init_hook = alc262_ultra_automute,
12685 },
Jiang zhe0e31daf2008-03-20 12:12:39 +010012686 [ALC262_LENOVO_3000] = {
12687 .mixers = { alc262_lenovo_3000_mixer },
12688 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
Daniel T Chene2595322009-12-19 18:19:02 -050012689 alc262_lenovo_3000_unsol_verbs,
12690 alc262_lenovo_3000_init_verbs },
Jiang zhe0e31daf2008-03-20 12:12:39 +010012691 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12692 .dac_nids = alc262_dac_nids,
12693 .hp_nid = 0x03,
12694 .dig_out_nid = ALC262_DIGOUT_NID,
12695 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12696 .channel_mode = alc262_modes,
12697 .input_mux = &alc262_fujitsu_capture_source,
12698 .unsol_event = alc262_lenovo_3000_unsol_event,
12699 },
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012700 [ALC262_NEC] = {
12701 .mixers = { alc262_nec_mixer },
12702 .init_verbs = { alc262_nec_verbs },
12703 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12704 .dac_nids = alc262_dac_nids,
12705 .hp_nid = 0x03,
12706 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12707 .channel_mode = alc262_modes,
12708 .input_mux = &alc262_capture_source,
12709 },
Kailang Yang4e555fe2008-08-26 13:05:55 +020012710 [ALC262_TOSHIBA_S06] = {
12711 .mixers = { alc262_toshiba_s06_mixer },
12712 .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
12713 alc262_eapd_verbs },
12714 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12715 .capsrc_nids = alc262_dmic_capsrc_nids,
12716 .dac_nids = alc262_dac_nids,
12717 .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
Takashi Iwaiae14ef62009-06-22 08:16:56 +020012718 .num_adc_nids = 1, /* single ADC */
Kailang Yang4e555fe2008-08-26 13:05:55 +020012719 .dig_out_nid = ALC262_DIGOUT_NID,
12720 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12721 .channel_mode = alc262_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012722 .unsol_event = alc_sku_unsol_event,
12723 .setup = alc262_toshiba_s06_setup,
12724 .init_hook = alc_inithook,
Kailang Yang4e555fe2008-08-26 13:05:55 +020012725 },
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012726 [ALC262_TOSHIBA_RX1] = {
12727 .mixers = { alc262_toshiba_rx1_mixer },
12728 .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
12729 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12730 .dac_nids = alc262_dac_nids,
12731 .hp_nid = 0x03,
12732 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12733 .channel_mode = alc262_modes,
12734 .input_mux = &alc262_capture_source,
12735 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012736 .setup = alc262_hippo_setup,
12737 .init_hook = alc262_hippo_automute,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012738 },
Tony Vroonba340e82009-02-02 19:01:30 +000012739 [ALC262_TYAN] = {
12740 .mixers = { alc262_tyan_mixer },
12741 .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
12742 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12743 .dac_nids = alc262_dac_nids,
12744 .hp_nid = 0x02,
12745 .dig_out_nid = ALC262_DIGOUT_NID,
12746 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12747 .channel_mode = alc262_modes,
12748 .input_mux = &alc262_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012749 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012750 .setup = alc262_tyan_setup,
12751 .init_hook = alc_automute_amp,
Tony Vroonba340e82009-02-02 19:01:30 +000012752 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012753};
12754
12755static int patch_alc262(struct hda_codec *codec)
12756{
12757 struct alc_spec *spec;
12758 int board_config;
12759 int err;
12760
Robert P. J. Daydc041e02006-12-19 14:44:15 +010012761 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010012762 if (spec == NULL)
12763 return -ENOMEM;
12764
12765 codec->spec = spec;
12766#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012767 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
12768 * under-run
12769 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012770 {
12771 int tmp;
12772 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
12773 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
12774 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
12775 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
12776 }
12777#endif
Kailang Yangda00c242010-03-19 11:23:45 +010012778 alc_auto_parse_customize_define(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012779
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020012780 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
12781
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012782 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
12783 alc262_models,
12784 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +010012785
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012786 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020012787 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
12788 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010012789 board_config = ALC262_AUTO;
12790 }
12791
Takashi Iwai18675e42010-09-08 15:55:44 +020012792 if (board_config == ALC262_AUTO)
12793 alc_pick_fixup(codec, alc262_fixup_tbl, alc262_fixups, 1);
12794
Kailang Yangdf694da2005-12-05 19:42:22 +010012795 if (board_config == ALC262_AUTO) {
12796 /* automatic parse from the BIOS config */
12797 err = alc262_parse_auto_config(codec);
12798 if (err < 0) {
12799 alc_free(codec);
12800 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012801 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012802 printk(KERN_INFO
12803 "hda_codec: Cannot set up configuration "
12804 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010012805 board_config = ALC262_BASIC;
12806 }
12807 }
12808
Takashi Iwaidc1eae22010-07-29 15:30:02 +020012809 if (!spec->no_analog && has_cdefine_beep(codec)) {
Takashi Iwai07eba612009-02-19 08:06:35 +010012810 err = snd_hda_attach_beep_device(codec, 0x1);
12811 if (err < 0) {
12812 alc_free(codec);
12813 return err;
12814 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090012815 }
12816
Kailang Yangdf694da2005-12-05 19:42:22 +010012817 if (board_config != ALC262_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020012818 setup_preset(codec, &alc262_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010012819
Kailang Yangdf694da2005-12-05 19:42:22 +010012820 spec->stream_analog_playback = &alc262_pcm_analog_playback;
12821 spec->stream_analog_capture = &alc262_pcm_analog_capture;
Kailang Yangea1fb292008-08-26 12:58:38 +020012822
Kailang Yangdf694da2005-12-05 19:42:22 +010012823 spec->stream_digital_playback = &alc262_pcm_digital_playback;
12824 spec->stream_digital_capture = &alc262_pcm_digital_capture;
12825
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012826 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwai8c927b42009-06-22 10:56:54 +020012827 int i;
12828 /* check whether the digital-mic has to be supported */
12829 for (i = 0; i < spec->input_mux->num_items; i++) {
12830 if (spec->input_mux->items[i].index >= 9)
12831 break;
12832 }
12833 if (i < spec->input_mux->num_items) {
12834 /* use only ADC0 */
12835 spec->adc_nids = alc262_dmic_adc_nids;
12836 spec->num_adc_nids = 1;
12837 spec->capsrc_nids = alc262_dmic_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +010012838 } else {
Takashi Iwai8c927b42009-06-22 10:56:54 +020012839 /* all analog inputs */
12840 /* check whether NID 0x07 is valid */
12841 unsigned int wcap = get_wcaps(codec, 0x07);
12842
12843 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020012844 wcap = get_wcaps_type(wcap);
Takashi Iwai8c927b42009-06-22 10:56:54 +020012845 if (wcap != AC_WID_AUD_IN) {
12846 spec->adc_nids = alc262_adc_nids_alt;
12847 spec->num_adc_nids =
12848 ARRAY_SIZE(alc262_adc_nids_alt);
12849 spec->capsrc_nids = alc262_capsrc_nids_alt;
12850 } else {
12851 spec->adc_nids = alc262_adc_nids;
12852 spec->num_adc_nids =
12853 ARRAY_SIZE(alc262_adc_nids);
12854 spec->capsrc_nids = alc262_capsrc_nids;
12855 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012856 }
12857 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012858 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020012859 set_capture_mixer(codec);
Takashi Iwaidc1eae22010-07-29 15:30:02 +020012860 if (!spec->no_analog && has_cdefine_beep(codec))
Takashi Iwai07eba612009-02-19 08:06:35 +010012861 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Kailang Yangdf694da2005-12-05 19:42:22 +010012862
Takashi Iwai18675e42010-09-08 15:55:44 +020012863 if (board_config == ALC262_AUTO)
12864 alc_pick_fixup(codec, alc262_fixup_tbl, alc262_fixups, 0);
12865
Takashi Iwai2134ea42008-01-10 16:53:55 +010012866 spec->vmaster_nid = 0x0c;
12867
Kailang Yangdf694da2005-12-05 19:42:22 +010012868 codec->patch_ops = alc_patch_ops;
12869 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012870 spec->init_hook = alc262_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020012871#ifdef CONFIG_SND_HDA_POWER_SAVE
12872 if (!spec->loopback.amplist)
12873 spec->loopback.amplist = alc262_loopbacks;
12874#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020012875
Kailang Yangdf694da2005-12-05 19:42:22 +010012876 return 0;
12877}
12878
Kailang Yangdf694da2005-12-05 19:42:22 +010012879/*
Kailang Yanga361d842007-06-05 12:30:55 +020012880 * ALC268 channel source setting (2 channel)
12881 */
12882#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
12883#define alc268_modes alc260_modes
Kailang Yangea1fb292008-08-26 12:58:38 +020012884
Kailang Yanga361d842007-06-05 12:30:55 +020012885static hda_nid_t alc268_dac_nids[2] = {
12886 /* front, hp */
12887 0x02, 0x03
12888};
12889
12890static hda_nid_t alc268_adc_nids[2] = {
12891 /* ADC0-1 */
12892 0x08, 0x07
12893};
12894
12895static hda_nid_t alc268_adc_nids_alt[1] = {
12896 /* ADC0 */
12897 0x08
12898};
12899
Takashi Iwaie1406342008-02-11 18:32:32 +010012900static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
12901
Kailang Yanga361d842007-06-05 12:30:55 +020012902static struct snd_kcontrol_new alc268_base_mixer[] = {
12903 /* output mixer control */
12904 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12905 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12906 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12907 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai33bf17a2007-08-21 11:51:42 +020012908 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12909 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12910 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +020012911 { }
12912};
12913
Takashi Iwai42171c12009-05-08 14:11:43 +020012914static struct snd_kcontrol_new alc268_toshiba_mixer[] = {
12915 /* output mixer control */
12916 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12917 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12918 ALC262_HIPPO_MASTER_SWITCH,
12919 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12920 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12921 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
12922 { }
12923};
12924
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012925/* bind Beep switches of both NID 0x0f and 0x10 */
12926static struct hda_bind_ctls alc268_bind_beep_sw = {
12927 .ops = &snd_hda_bind_sw,
12928 .values = {
12929 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
12930 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
12931 0
12932 },
12933};
12934
12935static struct snd_kcontrol_new alc268_beep_mixer[] = {
12936 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
12937 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
12938 { }
12939};
12940
Kailang Yangd1a991a2007-08-15 16:21:59 +020012941static struct hda_verb alc268_eapd_verbs[] = {
12942 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
12943 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
12944 { }
12945};
12946
Takashi Iwaid2738092007-08-16 14:59:45 +020012947/* Toshiba specific */
Takashi Iwaid2738092007-08-16 14:59:45 +020012948static struct hda_verb alc268_toshiba_verbs[] = {
12949 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12950 { } /* end */
12951};
12952
12953/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +020012954/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +020012955static struct hda_bind_ctls alc268_acer_bind_master_vol = {
12956 .ops = &snd_hda_bind_vol,
12957 .values = {
12958 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
12959 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
12960 0
12961 },
12962};
12963
Takashi Iwai889c4392007-08-23 18:56:52 +020012964/* mute/unmute internal speaker according to the hp jack and mute state */
12965static void alc268_acer_automute(struct hda_codec *codec, int force)
12966{
12967 struct alc_spec *spec = codec->spec;
12968 unsigned int mute;
12969
12970 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080012971 spec->jack_present = snd_hda_jack_detect(codec, 0x14);
Takashi Iwai889c4392007-08-23 18:56:52 +020012972 spec->sense_updated = 1;
12973 }
12974 if (spec->jack_present)
12975 mute = HDA_AMP_MUTE; /* mute internal speaker */
12976 else /* unmute internal speaker if necessary */
12977 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
12978 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
12979 HDA_AMP_MUTE, mute);
12980}
12981
12982
12983/* bind hp and internal speaker mute (with plug check) */
12984static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
12985 struct snd_ctl_elem_value *ucontrol)
12986{
12987 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
12988 long *valp = ucontrol->value.integer.value;
12989 int change;
12990
Takashi Iwai8de56b72009-07-24 16:51:47 +020012991 change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
Takashi Iwai889c4392007-08-23 18:56:52 +020012992 if (change)
12993 alc268_acer_automute(codec, 0);
12994 return change;
12995}
Takashi Iwaid2738092007-08-16 14:59:45 +020012996
Kailang Yang8ef355d2008-08-26 13:10:22 +020012997static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
12998 /* output mixer control */
12999 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13000 {
13001 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13002 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013003 .subdevice = HDA_SUBDEV_AMP_FLAG,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013004 .info = snd_hda_mixer_amp_switch_info,
13005 .get = snd_hda_mixer_amp_switch_get,
13006 .put = alc268_acer_master_sw_put,
13007 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13008 },
13009 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
13010 { }
13011};
13012
Takashi Iwaid2738092007-08-16 14:59:45 +020013013static struct snd_kcontrol_new alc268_acer_mixer[] = {
13014 /* output mixer control */
13015 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13016 {
13017 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13018 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013019 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwaid2738092007-08-16 14:59:45 +020013020 .info = snd_hda_mixer_amp_switch_info,
13021 .get = snd_hda_mixer_amp_switch_get,
13022 .put = alc268_acer_master_sw_put,
13023 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13024 },
Takashi Iwai33bf17a2007-08-21 11:51:42 +020013025 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13026 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
13027 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +020013028 { }
13029};
13030
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013031static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
13032 /* output mixer control */
13033 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13034 {
13035 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13036 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013037 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013038 .info = snd_hda_mixer_amp_switch_info,
13039 .get = snd_hda_mixer_amp_switch_get,
13040 .put = alc268_acer_master_sw_put,
13041 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13042 },
13043 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13044 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
13045 { }
13046};
13047
Kailang Yang8ef355d2008-08-26 13:10:22 +020013048static struct hda_verb alc268_acer_aspire_one_verbs[] = {
13049 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13050 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13051 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13052 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13053 {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
13054 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
13055 { }
13056};
13057
Takashi Iwaid2738092007-08-16 14:59:45 +020013058static struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013059 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
13060 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +020013061 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13062 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013063 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13064 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +020013065 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13066 { }
13067};
13068
13069/* unsolicited event for HP jack sensing */
Takashi Iwai42171c12009-05-08 14:11:43 +020013070#define alc268_toshiba_unsol_event alc262_hippo_unsol_event
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013071#define alc268_toshiba_setup alc262_hippo_setup
13072#define alc268_toshiba_automute alc262_hippo_automute
Takashi Iwaid2738092007-08-16 14:59:45 +020013073
13074static void alc268_acer_unsol_event(struct hda_codec *codec,
13075 unsigned int res)
13076{
Takashi Iwai889c4392007-08-23 18:56:52 +020013077 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020013078 return;
13079 alc268_acer_automute(codec, 1);
13080}
13081
Takashi Iwai889c4392007-08-23 18:56:52 +020013082static void alc268_acer_init_hook(struct hda_codec *codec)
13083{
13084 alc268_acer_automute(codec, 1);
13085}
13086
Kailang Yang8ef355d2008-08-26 13:10:22 +020013087/* toggle speaker-output according to the hp-jack state */
13088static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
13089{
13090 unsigned int present;
13091 unsigned char bits;
13092
Wu Fengguang864f92b2009-11-18 12:38:02 +080013093 present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013094 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang8ef355d2008-08-26 13:10:22 +020013095 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013096 HDA_AMP_MUTE, bits);
Kailang Yang8ef355d2008-08-26 13:10:22 +020013097 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013098 HDA_AMP_MUTE, bits);
Kailang Yang8ef355d2008-08-26 13:10:22 +020013099}
13100
Kailang Yang8ef355d2008-08-26 13:10:22 +020013101static void alc268_acer_lc_unsol_event(struct hda_codec *codec,
13102 unsigned int res)
13103{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013104 switch (res >> 26) {
13105 case ALC880_HP_EVENT:
Kailang Yang8ef355d2008-08-26 13:10:22 +020013106 alc268_aspire_one_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013107 break;
13108 case ALC880_MIC_EVENT:
13109 alc_mic_automute(codec);
13110 break;
13111 }
13112}
13113
13114static void alc268_acer_lc_setup(struct hda_codec *codec)
13115{
13116 struct alc_spec *spec = codec->spec;
13117 spec->ext_mic.pin = 0x18;
13118 spec->ext_mic.mux_idx = 0;
13119 spec->int_mic.pin = 0x12;
13120 spec->int_mic.mux_idx = 6;
13121 spec->auto_mic = 1;
Kailang Yang8ef355d2008-08-26 13:10:22 +020013122}
13123
13124static void alc268_acer_lc_init_hook(struct hda_codec *codec)
13125{
13126 alc268_aspire_one_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013127 alc_mic_automute(codec);
Kailang Yang8ef355d2008-08-26 13:10:22 +020013128}
13129
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013130static struct snd_kcontrol_new alc268_dell_mixer[] = {
13131 /* output mixer control */
13132 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13133 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13134 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13135 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
13136 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13137 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
13138 { }
13139};
13140
13141static struct hda_verb alc268_dell_verbs[] = {
13142 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13143 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13144 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013145 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013146 { }
13147};
13148
13149/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013150static void alc268_dell_setup(struct hda_codec *codec)
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013151{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013152 struct alc_spec *spec = codec->spec;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013153
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013154 spec->autocfg.hp_pins[0] = 0x15;
13155 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013156 spec->ext_mic.pin = 0x18;
13157 spec->ext_mic.mux_idx = 0;
13158 spec->int_mic.pin = 0x19;
13159 spec->int_mic.mux_idx = 1;
13160 spec->auto_mic = 1;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013161}
13162
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013163static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
13164 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
13165 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13166 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
13167 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
13168 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13169 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
13170 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
13171 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
13172 { }
13173};
13174
13175static struct hda_verb alc267_quanta_il1_verbs[] = {
13176 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13177 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
13178 { }
13179};
13180
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013181static void alc267_quanta_il1_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013182{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013183 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013184 spec->autocfg.hp_pins[0] = 0x15;
13185 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013186 spec->ext_mic.pin = 0x18;
13187 spec->ext_mic.mux_idx = 0;
13188 spec->int_mic.pin = 0x19;
13189 spec->int_mic.mux_idx = 1;
13190 spec->auto_mic = 1;
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013191}
13192
Kailang Yanga361d842007-06-05 12:30:55 +020013193/*
13194 * generic initialization of ADC, input mixers and output mixers
13195 */
13196static struct hda_verb alc268_base_init_verbs[] = {
13197 /* Unmute DAC0-1 and set vol = 0 */
13198 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020013199 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020013200
13201 /*
13202 * Set up output mixers (0x0c - 0x0e)
13203 */
13204 /* set vol=0 to output mixers */
13205 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020013206 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
13207
13208 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13209 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13210
13211 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
13212 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
13213 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
13214 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13215 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13216 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13217 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13218 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13219
13220 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13221 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13222 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13223 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013224 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013225
13226 /* set PCBEEP vol = 0, mute connections */
13227 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13228 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13229 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020013230
Jiang Zhea9b3aa82007-12-20 13:13:13 +010013231 /* Unmute Selector 23h,24h and set the default input to mic-in */
Kailang Yangea1fb292008-08-26 12:58:38 +020013232
Jiang Zhea9b3aa82007-12-20 13:13:13 +010013233 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
13234 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13235 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
13236 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013237
Kailang Yanga361d842007-06-05 12:30:55 +020013238 { }
13239};
13240
13241/*
13242 * generic initialization of ADC, input mixers and output mixers
13243 */
13244static struct hda_verb alc268_volume_init_verbs[] = {
13245 /* set output DAC */
Takashi Iwai4cfb91c2009-01-23 12:53:09 +010013246 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13247 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020013248
13249 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13250 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13251 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13252 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13253 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13254
Kailang Yanga361d842007-06-05 12:30:55 +020013255 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020013256 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13257 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13258
13259 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013260 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013261
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013262 /* set PCBEEP vol = 0, mute connections */
13263 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13264 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13265 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020013266
13267 { }
13268};
13269
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013270static struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = {
13271 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13272 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
13273 { } /* end */
13274};
13275
Kailang Yanga361d842007-06-05 12:30:55 +020013276static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
13277 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13278 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013279 _DEFINE_CAPSRC(1),
Kailang Yanga361d842007-06-05 12:30:55 +020013280 { } /* end */
13281};
13282
13283static struct snd_kcontrol_new alc268_capture_mixer[] = {
13284 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13285 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
13286 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
13287 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013288 _DEFINE_CAPSRC(2),
Kailang Yanga361d842007-06-05 12:30:55 +020013289 { } /* end */
13290};
13291
13292static struct hda_input_mux alc268_capture_source = {
13293 .num_items = 4,
13294 .items = {
13295 { "Mic", 0x0 },
13296 { "Front Mic", 0x1 },
13297 { "Line", 0x2 },
13298 { "CD", 0x3 },
13299 },
13300};
13301
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013302static struct hda_input_mux alc268_acer_capture_source = {
13303 .num_items = 3,
13304 .items = {
13305 { "Mic", 0x0 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013306 { "Internal Mic", 0x1 },
13307 { "Line", 0x2 },
13308 },
13309};
13310
13311static struct hda_input_mux alc268_acer_dmic_capture_source = {
13312 .num_items = 3,
13313 .items = {
13314 { "Mic", 0x0 },
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013315 { "Internal Mic", 0x6 },
13316 { "Line", 0x2 },
13317 },
13318};
13319
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013320#ifdef CONFIG_SND_DEBUG
13321static struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013322 /* Volume widgets */
13323 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13324 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13325 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
13326 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
13327 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
13328 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
13329 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
13330 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
13331 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
13332 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
13333 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
13334 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
13335 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010013336 /* The below appears problematic on some hardwares */
13337 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013338 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13339 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
13340 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
13341 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
13342
13343 /* Modes for retasking pin widgets */
13344 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
13345 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
13346 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
13347 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
13348
13349 /* Controls for GPIO pins, assuming they are configured as outputs */
13350 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
13351 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
13352 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
13353 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
13354
13355 /* Switches to allow the digital SPDIF output pin to be enabled.
13356 * The ALC268 does not have an SPDIF input.
13357 */
13358 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
13359
13360 /* A switch allowing EAPD to be enabled. Some laptops seem to use
13361 * this output to turn on an external amplifier.
13362 */
13363 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
13364 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
13365
13366 { } /* end */
13367};
13368#endif
13369
Kailang Yanga361d842007-06-05 12:30:55 +020013370/* create input playback/capture controls for the given pin */
13371static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
13372 const char *ctlname, int idx)
13373{
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013374 hda_nid_t dac;
Kailang Yanga361d842007-06-05 12:30:55 +020013375 int err;
13376
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013377 switch (nid) {
13378 case 0x14:
13379 case 0x16:
13380 dac = 0x02;
13381 break;
13382 case 0x15:
Takashi Iwaib08b1632010-07-30 14:08:25 +020013383 case 0x1a: /* ALC259/269 only */
13384 case 0x1b: /* ALC259/269 only */
Kailang Yang531d8792010-04-09 10:57:33 +020013385 case 0x21: /* ALC269vb has this pin, too */
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013386 dac = 0x03;
13387 break;
13388 default:
Takashi Iwaic7a94342010-07-30 14:10:43 +020013389 snd_printd(KERN_WARNING "hda_codec: "
13390 "ignoring pin 0x%x as unknown\n", nid);
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013391 return 0;
13392 }
13393 if (spec->multiout.dac_nids[0] != dac &&
13394 spec->multiout.dac_nids[1] != dac) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013395 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013396 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
Kailang Yanga361d842007-06-05 12:30:55 +020013397 HDA_OUTPUT));
13398 if (err < 0)
13399 return err;
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013400 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
13401 }
13402
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013403 if (nid != 0x16)
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013404 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Kailang Yanga361d842007-06-05 12:30:55 +020013405 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013406 else /* mono */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013407 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013408 HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013409 if (err < 0)
13410 return err;
13411 return 0;
13412}
13413
13414/* add playback controls from the parsed DAC table */
13415static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
13416 const struct auto_pin_cfg *cfg)
13417{
13418 hda_nid_t nid;
13419 int err;
13420
Kailang Yanga361d842007-06-05 12:30:55 +020013421 spec->multiout.dac_nids = spec->private_dac_nids;
Kailang Yanga361d842007-06-05 12:30:55 +020013422
13423 nid = cfg->line_out_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013424 if (nid) {
13425 const char *name;
13426 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
13427 name = "Speaker";
13428 else
13429 name = "Front";
13430 err = alc268_new_analog_output(spec, nid, name, 0);
13431 if (err < 0)
13432 return err;
13433 }
Kailang Yanga361d842007-06-05 12:30:55 +020013434
13435 nid = cfg->speaker_pins[0];
13436 if (nid == 0x1d) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013437 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Speaker",
Kailang Yanga361d842007-06-05 12:30:55 +020013438 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
13439 if (err < 0)
13440 return err;
David Henningsson7bfb9c02010-08-02 13:13:25 +020013441 } else if (nid) {
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013442 err = alc268_new_analog_output(spec, nid, "Speaker", 0);
13443 if (err < 0)
13444 return err;
Kailang Yanga361d842007-06-05 12:30:55 +020013445 }
13446 nid = cfg->hp_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013447 if (nid) {
13448 err = alc268_new_analog_output(spec, nid, "Headphone", 0);
13449 if (err < 0)
13450 return err;
13451 }
Kailang Yanga361d842007-06-05 12:30:55 +020013452
13453 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
13454 if (nid == 0x16) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013455 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, "Mono",
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013456 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013457 if (err < 0)
13458 return err;
13459 }
Kailang Yangea1fb292008-08-26 12:58:38 +020013460 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020013461}
13462
13463/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020013464static int alc268_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yanga361d842007-06-05 12:30:55 +020013465 const struct auto_pin_cfg *cfg)
13466{
Takashi Iwai05f5f472009-08-25 13:10:18 +020013467 return alc_auto_create_input_ctls(codec, cfg, 0, 0x23, 0x24);
Kailang Yanga361d842007-06-05 12:30:55 +020013468}
13469
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013470static void alc268_auto_set_output_and_unmute(struct hda_codec *codec,
13471 hda_nid_t nid, int pin_type)
13472{
13473 int idx;
13474
13475 alc_set_pin_output(codec, nid, pin_type);
13476 if (nid == 0x14 || nid == 0x16)
13477 idx = 0;
13478 else
13479 idx = 1;
13480 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
13481}
13482
13483static void alc268_auto_init_multi_out(struct hda_codec *codec)
13484{
13485 struct alc_spec *spec = codec->spec;
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013486 int i;
13487
13488 for (i = 0; i < spec->autocfg.line_outs; i++) {
13489 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013490 int pin_type = get_pin_type(spec->autocfg.line_out_type);
13491 alc268_auto_set_output_and_unmute(codec, nid, pin_type);
13492 }
13493}
13494
13495static void alc268_auto_init_hp_out(struct hda_codec *codec)
13496{
13497 struct alc_spec *spec = codec->spec;
13498 hda_nid_t pin;
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013499 int i;
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013500
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013501 for (i = 0; i < spec->autocfg.hp_outs; i++) {
13502 pin = spec->autocfg.hp_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013503 alc268_auto_set_output_and_unmute(codec, pin, PIN_HP);
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013504 }
13505 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
13506 pin = spec->autocfg.speaker_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013507 alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT);
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013508 }
13509 if (spec->autocfg.mono_out_pin)
13510 snd_hda_codec_write(codec, spec->autocfg.mono_out_pin, 0,
13511 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013512}
13513
Kailang Yanga361d842007-06-05 12:30:55 +020013514static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
13515{
13516 struct alc_spec *spec = codec->spec;
13517 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
13518 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
13519 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
13520 unsigned int dac_vol1, dac_vol2;
13521
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013522 if (line_nid == 0x1d || speaker_nid == 0x1d) {
Kailang Yanga361d842007-06-05 12:30:55 +020013523 snd_hda_codec_write(codec, speaker_nid, 0,
13524 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013525 /* mute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013526 snd_hda_codec_write(codec, 0x0f, 0,
13527 AC_VERB_SET_AMP_GAIN_MUTE,
13528 AMP_IN_UNMUTE(1));
13529 snd_hda_codec_write(codec, 0x10, 0,
13530 AC_VERB_SET_AMP_GAIN_MUTE,
13531 AMP_IN_UNMUTE(1));
13532 } else {
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013533 /* unmute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013534 snd_hda_codec_write(codec, 0x0f, 0,
13535 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13536 snd_hda_codec_write(codec, 0x10, 0,
13537 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13538 }
13539
13540 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020013541 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013542 dac_vol2 = AMP_OUT_ZERO;
13543 else if (line_nid == 0x15)
13544 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020013545 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013546 dac_vol2 = AMP_OUT_ZERO;
13547 else if (hp_nid == 0x15)
13548 dac_vol1 = AMP_OUT_ZERO;
13549 if (line_nid != 0x16 || hp_nid != 0x16 ||
13550 spec->autocfg.line_out_pins[1] != 0x16 ||
13551 spec->autocfg.line_out_pins[2] != 0x16)
13552 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
13553
13554 snd_hda_codec_write(codec, 0x02, 0,
13555 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
13556 snd_hda_codec_write(codec, 0x03, 0,
13557 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
13558}
13559
Sasha Alexandrdef319f2009-06-16 16:00:15 -040013560/* pcm configuration: identical with ALC880 */
Kailang Yanga361d842007-06-05 12:30:55 +020013561#define alc268_pcm_analog_playback alc880_pcm_analog_playback
13562#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010013563#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020013564#define alc268_pcm_digital_playback alc880_pcm_digital_playback
13565
13566/*
13567 * BIOS auto configuration
13568 */
13569static int alc268_parse_auto_config(struct hda_codec *codec)
13570{
13571 struct alc_spec *spec = codec->spec;
13572 int err;
13573 static hda_nid_t alc268_ignore[] = { 0 };
13574
13575 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13576 alc268_ignore);
13577 if (err < 0)
13578 return err;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013579 if (!spec->autocfg.line_outs) {
13580 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
13581 spec->multiout.max_channels = 2;
13582 spec->no_analog = 1;
13583 goto dig_only;
13584 }
Kailang Yanga361d842007-06-05 12:30:55 +020013585 return 0; /* can't find valid BIOS pin config */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013586 }
Kailang Yanga361d842007-06-05 12:30:55 +020013587 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
13588 if (err < 0)
13589 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020013590 err = alc268_auto_create_input_ctls(codec, &spec->autocfg);
Kailang Yanga361d842007-06-05 12:30:55 +020013591 if (err < 0)
13592 return err;
13593
13594 spec->multiout.max_channels = 2;
13595
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013596 dig_only:
Kailang Yanga361d842007-06-05 12:30:55 +020013597 /* digital only support output */
Takashi Iwai757899a2010-07-30 10:48:14 +020013598 alc_auto_parse_digital(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +020013599 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013600 add_mixer(spec, spec->kctls.list);
Kailang Yanga361d842007-06-05 12:30:55 +020013601
Takashi Iwai892981f2009-03-02 08:04:35 +010013602 if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013603 add_mixer(spec, alc268_beep_mixer);
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013604
Takashi Iwaid88897e2008-10-31 15:01:37 +010013605 add_verb(spec, alc268_volume_init_verbs);
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030013606 spec->num_mux_defs = 2;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020013607 spec->input_mux = &spec->private_imux[0];
Kailang Yanga361d842007-06-05 12:30:55 +020013608
Takashi Iwai776e1842007-08-29 15:07:11 +020013609 err = alc_auto_add_mic_boost(codec);
13610 if (err < 0)
13611 return err;
13612
Kailang Yang6227cdc2010-02-25 08:36:52 +010013613 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai1d955eb2009-06-29 11:33:53 +020013614
Kailang Yanga361d842007-06-05 12:30:55 +020013615 return 1;
13616}
13617
Kailang Yanga361d842007-06-05 12:30:55 +020013618#define alc268_auto_init_analog_input alc882_auto_init_analog_input
13619
13620/* init callback for auto-configuration model -- overriding the default init */
13621static void alc268_auto_init(struct hda_codec *codec)
13622{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013623 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020013624 alc268_auto_init_multi_out(codec);
13625 alc268_auto_init_hp_out(codec);
13626 alc268_auto_init_mono_speaker_out(codec);
13627 alc268_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020013628 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013629 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020013630 alc_inithook(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020013631}
13632
13633/*
13634 * configuration and preset
13635 */
13636static const char *alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013637 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020013638 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020013639 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020013640 [ALC268_ACER] = "acer",
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013641 [ALC268_ACER_DMIC] = "acer-dmic",
Kailang Yang8ef355d2008-08-26 13:10:22 +020013642 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013643 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013644 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013645#ifdef CONFIG_SND_DEBUG
13646 [ALC268_TEST] = "test",
13647#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013648 [ALC268_AUTO] = "auto",
13649};
13650
13651static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020013652 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013653 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010013654 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013655 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010013656 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020013657 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
13658 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013659 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Daniel T Chena1bf8082009-11-01 18:32:29 -050013660 SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0,
13661 "Dell Inspiron Mini9/Vostro A90", ALC268_DELL),
Takashi Iwai33d78672009-09-08 11:03:41 +020013662 /* almost compatible with toshiba but with optional digital outs;
13663 * auto-probing seems working fine
13664 */
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013665 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series",
Takashi Iwai33d78672009-09-08 11:03:41 +020013666 ALC268_AUTO),
Kailang Yanga361d842007-06-05 12:30:55 +020013667 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013668 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Tony Vroon378bd6a2008-06-04 12:08:30 +020013669 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020013670 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013671 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Kailang Yanga361d842007-06-05 12:30:55 +020013672 {}
13673};
13674
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013675/* Toshiba laptops have no unique PCI SSID but only codec SSID */
13676static struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
13677 SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO),
13678 SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO),
13679 SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
13680 ALC268_TOSHIBA),
13681 {}
13682};
13683
Kailang Yanga361d842007-06-05 12:30:55 +020013684static struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013685 [ALC267_QUANTA_IL1] = {
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013686 .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer,
13687 alc268_capture_nosrc_mixer },
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013688 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13689 alc267_quanta_il1_verbs },
13690 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13691 .dac_nids = alc268_dac_nids,
13692 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13693 .adc_nids = alc268_adc_nids_alt,
13694 .hp_nid = 0x03,
13695 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13696 .channel_mode = alc268_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013697 .unsol_event = alc_sku_unsol_event,
13698 .setup = alc267_quanta_il1_setup,
13699 .init_hook = alc_inithook,
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013700 },
Kailang Yanga361d842007-06-05 12:30:55 +020013701 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013702 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13703 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020013704 .init_verbs = { alc268_base_init_verbs },
13705 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13706 .dac_nids = alc268_dac_nids,
13707 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13708 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013709 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020013710 .hp_nid = 0x03,
13711 .dig_out_nid = ALC268_DIGOUT_NID,
13712 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13713 .channel_mode = alc268_modes,
13714 .input_mux = &alc268_capture_source,
13715 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013716 [ALC268_TOSHIBA] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020013717 .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013718 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013719 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13720 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013721 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13722 .dac_nids = alc268_dac_nids,
13723 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13724 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013725 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013726 .hp_nid = 0x03,
13727 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13728 .channel_mode = alc268_modes,
13729 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020013730 .unsol_event = alc268_toshiba_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013731 .setup = alc268_toshiba_setup,
13732 .init_hook = alc268_toshiba_automute,
Takashi Iwaid2738092007-08-16 14:59:45 +020013733 },
13734 [ALC268_ACER] = {
Takashi Iwai432fd132009-09-30 08:13:44 +020013735 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013736 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013737 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13738 alc268_acer_verbs },
13739 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13740 .dac_nids = alc268_dac_nids,
13741 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13742 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013743 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020013744 .hp_nid = 0x02,
13745 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13746 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013747 .input_mux = &alc268_acer_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020013748 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020013749 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013750 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013751 [ALC268_ACER_DMIC] = {
13752 .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
13753 alc268_beep_mixer },
13754 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13755 alc268_acer_verbs },
13756 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13757 .dac_nids = alc268_dac_nids,
13758 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13759 .adc_nids = alc268_adc_nids_alt,
13760 .capsrc_nids = alc268_capsrc_nids,
13761 .hp_nid = 0x02,
13762 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13763 .channel_mode = alc268_modes,
13764 .input_mux = &alc268_acer_dmic_capture_source,
13765 .unsol_event = alc268_acer_unsol_event,
13766 .init_hook = alc268_acer_init_hook,
13767 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013768 [ALC268_ACER_ASPIRE_ONE] = {
13769 .mixers = { alc268_acer_aspire_one_mixer,
Takashi Iwai22971e32009-02-10 11:56:44 +010013770 alc268_beep_mixer,
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013771 alc268_capture_nosrc_mixer },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013772 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13773 alc268_acer_aspire_one_verbs },
13774 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13775 .dac_nids = alc268_dac_nids,
13776 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13777 .adc_nids = alc268_adc_nids_alt,
13778 .capsrc_nids = alc268_capsrc_nids,
13779 .hp_nid = 0x03,
13780 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13781 .channel_mode = alc268_modes,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013782 .unsol_event = alc268_acer_lc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013783 .setup = alc268_acer_lc_setup,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013784 .init_hook = alc268_acer_lc_init_hook,
13785 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013786 [ALC268_DELL] = {
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013787 .mixers = { alc268_dell_mixer, alc268_beep_mixer,
13788 alc268_capture_nosrc_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013789 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13790 alc268_dell_verbs },
13791 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13792 .dac_nids = alc268_dac_nids,
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013793 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13794 .adc_nids = alc268_adc_nids_alt,
13795 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013796 .hp_nid = 0x02,
13797 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13798 .channel_mode = alc268_modes,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013799 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013800 .setup = alc268_dell_setup,
13801 .init_hook = alc_inithook,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013802 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013803 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013804 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13805 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013806 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13807 alc268_toshiba_verbs },
13808 .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,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013813 .hp_nid = 0x03,
13814 .dig_out_nid = ALC268_DIGOUT_NID,
13815 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13816 .channel_mode = alc268_modes,
13817 .input_mux = &alc268_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013818 .setup = alc268_toshiba_setup,
13819 .init_hook = alc268_toshiba_automute,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013820 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013821#ifdef CONFIG_SND_DEBUG
13822 [ALC268_TEST] = {
13823 .mixers = { alc268_test_mixer, alc268_capture_mixer },
13824 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13825 alc268_volume_init_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,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013831 .hp_nid = 0x03,
13832 .dig_out_nid = ALC268_DIGOUT_NID,
13833 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13834 .channel_mode = alc268_modes,
13835 .input_mux = &alc268_capture_source,
13836 },
13837#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013838};
13839
13840static int patch_alc268(struct hda_codec *codec)
13841{
13842 struct alc_spec *spec;
13843 int board_config;
Takashi Iwai22971e32009-02-10 11:56:44 +010013844 int i, has_beep, err;
Kailang Yanga361d842007-06-05 12:30:55 +020013845
Julia Lawallef86f582009-12-19 08:18:03 +010013846 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yanga361d842007-06-05 12:30:55 +020013847 if (spec == NULL)
13848 return -ENOMEM;
13849
13850 codec->spec = spec;
13851
13852 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
13853 alc268_models,
13854 alc268_cfg_tbl);
13855
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013856 if (board_config < 0 || board_config >= ALC268_MODEL_LAST)
13857 board_config = snd_hda_check_board_codec_sid_config(codec,
Takashi Iwai50ae0aa2010-03-08 12:09:59 +010013858 ALC268_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl);
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013859
Kailang Yanga361d842007-06-05 12:30:55 +020013860 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020013861 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
13862 codec->chip_name);
Kailang Yanga361d842007-06-05 12:30:55 +020013863 board_config = ALC268_AUTO;
13864 }
13865
13866 if (board_config == ALC268_AUTO) {
13867 /* automatic parse from the BIOS config */
13868 err = alc268_parse_auto_config(codec);
13869 if (err < 0) {
13870 alc_free(codec);
13871 return err;
13872 } else if (!err) {
13873 printk(KERN_INFO
13874 "hda_codec: Cannot set up configuration "
13875 "from BIOS. Using base mode...\n");
13876 board_config = ALC268_3ST;
13877 }
13878 }
13879
13880 if (board_config != ALC268_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020013881 setup_preset(codec, &alc268_presets[board_config]);
Kailang Yanga361d842007-06-05 12:30:55 +020013882
Kailang Yanga361d842007-06-05 12:30:55 +020013883 spec->stream_analog_playback = &alc268_pcm_analog_playback;
13884 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010013885 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020013886
Kailang Yanga361d842007-06-05 12:30:55 +020013887 spec->stream_digital_playback = &alc268_pcm_digital_playback;
13888
Takashi Iwai22971e32009-02-10 11:56:44 +010013889 has_beep = 0;
13890 for (i = 0; i < spec->num_mixers; i++) {
13891 if (spec->mixers[i] == alc268_beep_mixer) {
13892 has_beep = 1;
13893 break;
13894 }
13895 }
13896
13897 if (has_beep) {
13898 err = snd_hda_attach_beep_device(codec, 0x1);
13899 if (err < 0) {
13900 alc_free(codec);
13901 return err;
13902 }
13903 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
13904 /* override the amp caps for beep generator */
13905 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013906 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
13907 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
13908 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
13909 (0 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwai22971e32009-02-10 11:56:44 +010013910 }
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013911
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013912 if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013913 /* check whether NID 0x07 is valid */
13914 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwai85860c02008-02-19 15:00:15 +010013915 int i;
Kailang Yanga361d842007-06-05 12:30:55 +020013916
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020013917 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013918 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020013919 wcap = get_wcaps_type(wcap);
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013920 if (spec->auto_mic ||
13921 wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013922 spec->adc_nids = alc268_adc_nids_alt;
13923 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020013924 if (spec->auto_mic)
13925 fixup_automic_adc(codec);
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013926 if (spec->auto_mic || spec->input_mux->num_items == 1)
13927 add_mixer(spec, alc268_capture_nosrc_mixer);
13928 else
13929 add_mixer(spec, alc268_capture_alt_mixer);
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013930 } else {
13931 spec->adc_nids = alc268_adc_nids;
13932 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
Takashi Iwaid88897e2008-10-31 15:01:37 +010013933 add_mixer(spec, alc268_capture_mixer);
Kailang Yanga361d842007-06-05 12:30:55 +020013934 }
Takashi Iwai85860c02008-02-19 15:00:15 +010013935 /* set default input source */
13936 for (i = 0; i < spec->num_adc_nids; i++)
13937 snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
13938 0, AC_VERB_SET_CONNECT_SEL,
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030013939 i < spec->num_mux_defs ?
13940 spec->input_mux[i].items[0].index :
Takashi Iwai85860c02008-02-19 15:00:15 +010013941 spec->input_mux->items[0].index);
Kailang Yanga361d842007-06-05 12:30:55 +020013942 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010013943
13944 spec->vmaster_nid = 0x02;
13945
Kailang Yanga361d842007-06-05 12:30:55 +020013946 codec->patch_ops = alc_patch_ops;
13947 if (board_config == ALC268_AUTO)
13948 spec->init_hook = alc268_auto_init;
Kailang Yangea1fb292008-08-26 12:58:38 +020013949
Kailang Yanga361d842007-06-05 12:30:55 +020013950 return 0;
13951}
13952
13953/*
Kailang Yangf6a92242007-12-13 16:52:54 +010013954 * ALC269 channel source setting (2 channel)
13955 */
13956#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
13957
13958#define alc269_dac_nids alc260_dac_nids
13959
13960static hda_nid_t alc269_adc_nids[1] = {
13961 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020013962 0x08,
13963};
13964
Takashi Iwaie01bf502008-08-21 16:25:07 +020013965static hda_nid_t alc269_capsrc_nids[1] = {
13966 0x23,
13967};
13968
Kailang Yang84898e82010-02-04 14:16:14 +010013969static hda_nid_t alc269vb_adc_nids[1] = {
13970 /* ADC1 */
13971 0x09,
13972};
13973
13974static hda_nid_t alc269vb_capsrc_nids[1] = {
13975 0x22,
13976};
13977
Takashi Iwai66946352010-03-29 17:21:45 +020013978static hda_nid_t alc269_adc_candidates[] = {
13979 0x08, 0x09, 0x07,
13980};
Takashi Iwaie01bf502008-08-21 16:25:07 +020013981
Kailang Yangf6a92242007-12-13 16:52:54 +010013982#define alc269_modes alc260_modes
13983#define alc269_capture_source alc880_lg_lw_capture_source
13984
13985static struct snd_kcontrol_new alc269_base_mixer[] = {
13986 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13987 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13988 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13989 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13990 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13991 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13992 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13993 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13994 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
13995 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
13996 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
13997 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
13998 { } /* end */
13999};
14000
Kailang Yang60db6b52008-08-26 13:13:00 +020014001static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
14002 /* output mixer control */
14003 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
14004 {
14005 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14006 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010014007 .subdevice = HDA_SUBDEV_AMP_FLAG,
Kailang Yang60db6b52008-08-26 13:13:00 +020014008 .info = snd_hda_mixer_amp_switch_info,
14009 .get = snd_hda_mixer_amp_switch_get,
14010 .put = alc268_acer_master_sw_put,
14011 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14012 },
14013 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14014 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14015 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
14016 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
14017 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
14018 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020014019 { }
14020};
14021
Tony Vroon64154832008-11-06 15:08:49 +000014022static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
14023 /* output mixer control */
14024 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
14025 {
14026 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14027 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010014028 .subdevice = HDA_SUBDEV_AMP_FLAG,
Tony Vroon64154832008-11-06 15:08:49 +000014029 .info = snd_hda_mixer_amp_switch_info,
14030 .get = snd_hda_mixer_amp_switch_get,
14031 .put = alc268_acer_master_sw_put,
14032 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14033 },
14034 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14035 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14036 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
14037 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
14038 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
14039 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
14040 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
14041 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
14042 HDA_CODEC_VOLUME("Dock Mic Boost", 0x1b, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000014043 { }
14044};
14045
Kailang Yang84898e82010-02-04 14:16:14 +010014046static struct snd_kcontrol_new alc269_laptop_mixer[] = {
Takashi Iwaiaa202452009-07-03 15:00:54 +020014047 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010014048 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwaiaa202452009-07-03 15:00:54 +020014049 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010014050 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yangf53281e2008-07-18 12:36:43 +020014051 { } /* end */
14052};
14053
Kailang Yang84898e82010-02-04 14:16:14 +010014054static struct snd_kcontrol_new alc269vb_laptop_mixer[] = {
14055 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14056 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14057 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
14058 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14059 { } /* end */
14060};
14061
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014062static struct snd_kcontrol_new alc269_asus_mixer[] = {
14063 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14064 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x0, HDA_INPUT),
14065 { } /* end */
14066};
14067
Kailang Yangf6a92242007-12-13 16:52:54 +010014068/* capture mixer elements */
Kailang Yang84898e82010-02-04 14:16:14 +010014069static struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
14070 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
14071 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
14072 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
14073 HDA_CODEC_VOLUME("IntMic Boost", 0x19, 0, HDA_INPUT),
14074 { } /* end */
14075};
14076
14077static struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = {
Kailang Yangf53281e2008-07-18 12:36:43 +020014078 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
14079 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Takashi Iwai26f5df22008-11-03 17:39:46 +010014080 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
14081 { } /* end */
14082};
14083
Kailang Yang84898e82010-02-04 14:16:14 +010014084static struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
14085 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
14086 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
14087 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
14088 HDA_CODEC_VOLUME("IntMic Boost", 0x19, 0, HDA_INPUT),
14089 { } /* end */
14090};
14091
14092static struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
14093 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
14094 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
14095 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
14096 { } /* end */
14097};
14098
Takashi Iwai26f5df22008-11-03 17:39:46 +010014099/* FSC amilo */
Kailang Yang84898e82010-02-04 14:16:14 +010014100#define alc269_fujitsu_mixer alc269_laptop_mixer
Kailang Yangf53281e2008-07-18 12:36:43 +020014101
Kailang Yang60db6b52008-08-26 13:13:00 +020014102static struct hda_verb alc269_quanta_fl1_verbs[] = {
14103 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14104 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14105 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14106 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
14107 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14108 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14109 { }
14110};
14111
Tony Vroon64154832008-11-06 15:08:49 +000014112static struct hda_verb alc269_lifebook_verbs[] = {
14113 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14114 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
14115 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14116 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14117 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
14118 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14119 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14120 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
14121 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14122 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14123 { }
14124};
14125
Kailang Yang60db6b52008-08-26 13:13:00 +020014126/* toggle speaker-output according to the hp-jack state */
14127static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
14128{
14129 unsigned int present;
14130 unsigned char bits;
14131
Wu Fengguang864f92b2009-11-18 12:38:02 +080014132 present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014133 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang60db6b52008-08-26 13:13:00 +020014134 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014135 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020014136 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014137 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020014138
14139 snd_hda_codec_write(codec, 0x20, 0,
14140 AC_VERB_SET_COEF_INDEX, 0x0c);
14141 snd_hda_codec_write(codec, 0x20, 0,
14142 AC_VERB_SET_PROC_COEF, 0x680);
14143
14144 snd_hda_codec_write(codec, 0x20, 0,
14145 AC_VERB_SET_COEF_INDEX, 0x0c);
14146 snd_hda_codec_write(codec, 0x20, 0,
14147 AC_VERB_SET_PROC_COEF, 0x480);
14148}
14149
Tony Vroon64154832008-11-06 15:08:49 +000014150/* toggle speaker-output according to the hp-jacks state */
14151static void alc269_lifebook_speaker_automute(struct hda_codec *codec)
14152{
14153 unsigned int present;
14154 unsigned char bits;
14155
14156 /* Check laptop headphone socket */
Wu Fengguang864f92b2009-11-18 12:38:02 +080014157 present = snd_hda_jack_detect(codec, 0x15);
Tony Vroon64154832008-11-06 15:08:49 +000014158
14159 /* Check port replicator headphone socket */
Wu Fengguang864f92b2009-11-18 12:38:02 +080014160 present |= snd_hda_jack_detect(codec, 0x1a);
Tony Vroon64154832008-11-06 15:08:49 +000014161
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014162 bits = present ? HDA_AMP_MUTE : 0;
Tony Vroon64154832008-11-06 15:08:49 +000014163 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014164 HDA_AMP_MUTE, bits);
Tony Vroon64154832008-11-06 15:08:49 +000014165 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014166 HDA_AMP_MUTE, bits);
Tony Vroon64154832008-11-06 15:08:49 +000014167
14168 snd_hda_codec_write(codec, 0x20, 0,
14169 AC_VERB_SET_COEF_INDEX, 0x0c);
14170 snd_hda_codec_write(codec, 0x20, 0,
14171 AC_VERB_SET_PROC_COEF, 0x680);
14172
14173 snd_hda_codec_write(codec, 0x20, 0,
14174 AC_VERB_SET_COEF_INDEX, 0x0c);
14175 snd_hda_codec_write(codec, 0x20, 0,
14176 AC_VERB_SET_PROC_COEF, 0x480);
14177}
14178
Tony Vroon64154832008-11-06 15:08:49 +000014179static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
14180{
14181 unsigned int present_laptop;
14182 unsigned int present_dock;
14183
Wu Fengguang864f92b2009-11-18 12:38:02 +080014184 present_laptop = snd_hda_jack_detect(codec, 0x18);
14185 present_dock = snd_hda_jack_detect(codec, 0x1b);
Tony Vroon64154832008-11-06 15:08:49 +000014186
14187 /* Laptop mic port overrides dock mic port, design decision */
14188 if (present_dock)
14189 snd_hda_codec_write(codec, 0x23, 0,
14190 AC_VERB_SET_CONNECT_SEL, 0x3);
14191 if (present_laptop)
14192 snd_hda_codec_write(codec, 0x23, 0,
14193 AC_VERB_SET_CONNECT_SEL, 0x0);
14194 if (!present_dock && !present_laptop)
14195 snd_hda_codec_write(codec, 0x23, 0,
14196 AC_VERB_SET_CONNECT_SEL, 0x1);
14197}
14198
Kailang Yang60db6b52008-08-26 13:13:00 +020014199static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
14200 unsigned int res)
14201{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014202 switch (res >> 26) {
14203 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020014204 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014205 break;
14206 case ALC880_MIC_EVENT:
14207 alc_mic_automute(codec);
14208 break;
14209 }
Kailang Yang60db6b52008-08-26 13:13:00 +020014210}
14211
Tony Vroon64154832008-11-06 15:08:49 +000014212static void alc269_lifebook_unsol_event(struct hda_codec *codec,
14213 unsigned int res)
14214{
14215 if ((res >> 26) == ALC880_HP_EVENT)
14216 alc269_lifebook_speaker_automute(codec);
14217 if ((res >> 26) == ALC880_MIC_EVENT)
14218 alc269_lifebook_mic_autoswitch(codec);
14219}
14220
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014221static void alc269_quanta_fl1_setup(struct hda_codec *codec)
14222{
14223 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010014224 spec->autocfg.hp_pins[0] = 0x15;
14225 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014226 spec->ext_mic.pin = 0x18;
14227 spec->ext_mic.mux_idx = 0;
14228 spec->int_mic.pin = 0x19;
14229 spec->int_mic.mux_idx = 1;
14230 spec->auto_mic = 1;
14231}
14232
Kailang Yang60db6b52008-08-26 13:13:00 +020014233static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
14234{
14235 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014236 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020014237}
14238
Tony Vroon64154832008-11-06 15:08:49 +000014239static void alc269_lifebook_init_hook(struct hda_codec *codec)
14240{
14241 alc269_lifebook_speaker_automute(codec);
14242 alc269_lifebook_mic_autoswitch(codec);
14243}
14244
Kailang Yang84898e82010-02-04 14:16:14 +010014245static struct hda_verb alc269_laptop_dmic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014246 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14247 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
14248 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14249 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14250 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14251 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14252 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14253 {}
14254};
14255
Kailang Yang84898e82010-02-04 14:16:14 +010014256static struct hda_verb alc269_laptop_amic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014257 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14258 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
14259 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14260 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
14261 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14262 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14263 {}
14264};
14265
Kailang Yang84898e82010-02-04 14:16:14 +010014266static struct hda_verb alc269vb_laptop_dmic_init_verbs[] = {
14267 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
14268 {0x22, AC_VERB_SET_CONNECT_SEL, 0x06},
14269 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14270 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14271 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14272 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14273 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14274 {}
14275};
14276
14277static struct hda_verb alc269vb_laptop_amic_init_verbs[] = {
14278 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
14279 {0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
14280 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14281 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14282 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14283 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14284 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14285 {}
14286};
14287
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014288static struct hda_verb alc271_acer_dmic_verbs[] = {
14289 {0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
14290 {0x20, AC_VERB_SET_PROC_COEF, 0x4000},
14291 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14292 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14293 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14294 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14295 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00},
14296 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14297 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14298 {0x22, AC_VERB_SET_CONNECT_SEL, 6},
14299 { }
14300};
14301
Kailang Yang60db6b52008-08-26 13:13:00 +020014302/* toggle speaker-output according to the hp-jack state */
14303static void alc269_speaker_automute(struct hda_codec *codec)
14304{
Kailang Yangebb83ee2009-12-17 12:23:00 +010014305 struct alc_spec *spec = codec->spec;
14306 unsigned int nid = spec->autocfg.hp_pins[0];
Kailang Yang60db6b52008-08-26 13:13:00 +020014307 unsigned int present;
14308 unsigned char bits;
14309
Kailang Yangebb83ee2009-12-17 12:23:00 +010014310 present = snd_hda_jack_detect(codec, nid);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014311 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang60db6b52008-08-26 13:13:00 +020014312 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014313 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020014314 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014315 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020014316}
14317
Kailang Yang60db6b52008-08-26 13:13:00 +020014318/* unsolicited event for HP jack sensing */
Kailang Yang84898e82010-02-04 14:16:14 +010014319static void alc269_laptop_unsol_event(struct hda_codec *codec,
Kailang Yang60db6b52008-08-26 13:13:00 +020014320 unsigned int res)
14321{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014322 switch (res >> 26) {
14323 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020014324 alc269_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014325 break;
14326 case ALC880_MIC_EVENT:
14327 alc_mic_automute(codec);
14328 break;
14329 }
Kailang Yang60db6b52008-08-26 13:13:00 +020014330}
14331
Kailang Yang226b1ec2010-04-09 11:01:20 +020014332static void alc269_laptop_amic_setup(struct hda_codec *codec)
14333{
14334 struct alc_spec *spec = codec->spec;
14335 spec->autocfg.hp_pins[0] = 0x15;
14336 spec->autocfg.speaker_pins[0] = 0x14;
14337 spec->ext_mic.pin = 0x18;
14338 spec->ext_mic.mux_idx = 0;
14339 spec->int_mic.pin = 0x19;
14340 spec->int_mic.mux_idx = 1;
14341 spec->auto_mic = 1;
14342}
14343
Kailang Yang84898e82010-02-04 14:16:14 +010014344static void alc269_laptop_dmic_setup(struct hda_codec *codec)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014345{
14346 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010014347 spec->autocfg.hp_pins[0] = 0x15;
14348 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014349 spec->ext_mic.pin = 0x18;
14350 spec->ext_mic.mux_idx = 0;
14351 spec->int_mic.pin = 0x12;
14352 spec->int_mic.mux_idx = 5;
14353 spec->auto_mic = 1;
14354}
14355
Kailang Yang226b1ec2010-04-09 11:01:20 +020014356static void alc269vb_laptop_amic_setup(struct hda_codec *codec)
Kailang Yang84898e82010-02-04 14:16:14 +010014357{
14358 struct alc_spec *spec = codec->spec;
Kailang Yang226b1ec2010-04-09 11:01:20 +020014359 spec->autocfg.hp_pins[0] = 0x21;
Takashi Iwai20645d72010-03-02 11:14:01 +010014360 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014361 spec->ext_mic.pin = 0x18;
14362 spec->ext_mic.mux_idx = 0;
14363 spec->int_mic.pin = 0x19;
14364 spec->int_mic.mux_idx = 1;
14365 spec->auto_mic = 1;
14366}
14367
Kailang Yang226b1ec2010-04-09 11:01:20 +020014368static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
14369{
14370 struct alc_spec *spec = codec->spec;
14371 spec->autocfg.hp_pins[0] = 0x21;
14372 spec->autocfg.speaker_pins[0] = 0x14;
14373 spec->ext_mic.pin = 0x18;
14374 spec->ext_mic.mux_idx = 0;
14375 spec->int_mic.pin = 0x12;
14376 spec->int_mic.mux_idx = 6;
14377 spec->auto_mic = 1;
14378}
14379
Kailang Yang84898e82010-02-04 14:16:14 +010014380static void alc269_laptop_inithook(struct hda_codec *codec)
Kailang Yang60db6b52008-08-26 13:13:00 +020014381{
14382 alc269_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014383 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020014384}
14385
Kailang Yangf6a92242007-12-13 16:52:54 +010014386/*
14387 * generic initialization of ADC, input mixers and output mixers
14388 */
14389static struct hda_verb alc269_init_verbs[] = {
14390 /*
14391 * Unmute ADC0 and set the default input to mic-in
14392 */
Kailang Yang84898e82010-02-04 14:16:14 +010014393 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010014394
14395 /*
Kailang Yang84898e82010-02-04 14:16:14 +010014396 * Set up output mixers (0x02 - 0x03)
Kailang Yangf6a92242007-12-13 16:52:54 +010014397 */
14398 /* set vol=0 to output mixers */
14399 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14400 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14401
14402 /* set up input amps for analog loopback */
14403 /* Amp Indices: DAC = 0, mixer = 1 */
14404 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14405 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14406 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14407 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14408 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14409 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14410
14411 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14412 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14413 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14414 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14415 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14416 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14417 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14418
14419 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14420 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf6a92242007-12-13 16:52:54 +010014421
Kailang Yang84898e82010-02-04 14:16:14 +010014422 /* FIXME: use Mux-type input source selection */
Kailang Yangf6a92242007-12-13 16:52:54 +010014423 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14424 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang84898e82010-02-04 14:16:14 +010014425 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangf6a92242007-12-13 16:52:54 +010014426
14427 /* set EAPD */
14428 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yang84898e82010-02-04 14:16:14 +010014429 { }
14430};
14431
14432static struct hda_verb alc269vb_init_verbs[] = {
14433 /*
14434 * Unmute ADC0 and set the default input to mic-in
14435 */
14436 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14437
14438 /*
14439 * Set up output mixers (0x02 - 0x03)
14440 */
14441 /* set vol=0 to output mixers */
14442 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14443 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14444
14445 /* set up input amps for analog loopback */
14446 /* Amp Indices: DAC = 0, mixer = 1 */
14447 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14448 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14449 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14450 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14451 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14452 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14453
14454 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14455 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14456 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14457 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14458 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14459 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14460 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14461
14462 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14463 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14464
14465 /* FIXME: use Mux-type input source selection */
14466 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14467 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
14468 {0x22, AC_VERB_SET_CONNECT_SEL, 0x00},
14469
14470 /* set EAPD */
14471 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yangf6a92242007-12-13 16:52:54 +010014472 { }
14473};
14474
Takashi Iwai9d0b71b2009-08-24 14:10:30 +020014475#define alc269_auto_create_multi_out_ctls \
14476 alc268_auto_create_multi_out_ctls
Takashi Iwai05f5f472009-08-25 13:10:18 +020014477#define alc269_auto_create_input_ctls \
14478 alc268_auto_create_input_ctls
Kailang Yangf6a92242007-12-13 16:52:54 +010014479
14480#ifdef CONFIG_SND_HDA_POWER_SAVE
14481#define alc269_loopbacks alc880_loopbacks
14482#endif
14483
Sasha Alexandrdef319f2009-06-16 16:00:15 -040014484/* pcm configuration: identical with ALC880 */
Kailang Yangf6a92242007-12-13 16:52:54 +010014485#define alc269_pcm_analog_playback alc880_pcm_analog_playback
14486#define alc269_pcm_analog_capture alc880_pcm_analog_capture
14487#define alc269_pcm_digital_playback alc880_pcm_digital_playback
14488#define alc269_pcm_digital_capture alc880_pcm_digital_capture
14489
Takashi Iwaif03d3112009-03-05 14:18:16 +010014490static struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
14491 .substreams = 1,
14492 .channels_min = 2,
14493 .channels_max = 8,
14494 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14495 /* NID is set in alc_build_pcms */
14496 .ops = {
14497 .open = alc880_playback_pcm_open,
14498 .prepare = alc880_playback_pcm_prepare,
14499 .cleanup = alc880_playback_pcm_cleanup
14500 },
14501};
14502
14503static struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
14504 .substreams = 1,
14505 .channels_min = 2,
14506 .channels_max = 2,
14507 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14508 /* NID is set in alc_build_pcms */
14509};
14510
Takashi Iwaiad358792010-03-30 18:00:59 +020014511#ifdef CONFIG_SND_HDA_POWER_SAVE
14512static int alc269_mic2_for_mute_led(struct hda_codec *codec)
14513{
14514 switch (codec->subsystem_id) {
14515 case 0x103c1586:
14516 return 1;
14517 }
14518 return 0;
14519}
14520
14521static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
14522{
14523 /* update mute-LED according to the speaker mute state */
14524 if (nid == 0x01 || nid == 0x14) {
14525 int pinval;
14526 if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) &
14527 HDA_AMP_MUTE)
14528 pinval = 0x24;
14529 else
14530 pinval = 0x20;
14531 /* mic2 vref pin is used for mute LED control */
Takashi Iwaia68d5a542010-03-30 18:03:44 +020014532 snd_hda_codec_update_cache(codec, 0x19, 0,
14533 AC_VERB_SET_PIN_WIDGET_CONTROL,
14534 pinval);
Takashi Iwaiad358792010-03-30 18:00:59 +020014535 }
14536 return alc_check_power_status(codec, nid);
14537}
14538#endif /* CONFIG_SND_HDA_POWER_SAVE */
14539
Takashi Iwai840b64c2010-07-13 22:49:01 +020014540static int alc275_setup_dual_adc(struct hda_codec *codec)
14541{
14542 struct alc_spec *spec = codec->spec;
14543
14544 if (codec->vendor_id != 0x10ec0275 || !spec->auto_mic)
14545 return 0;
14546 if ((spec->ext_mic.pin >= 0x18 && spec->int_mic.pin <= 0x13) ||
14547 (spec->ext_mic.pin <= 0x12 && spec->int_mic.pin >= 0x18)) {
14548 if (spec->ext_mic.pin <= 0x12) {
14549 spec->private_adc_nids[0] = 0x08;
14550 spec->private_adc_nids[1] = 0x11;
14551 spec->private_capsrc_nids[0] = 0x23;
14552 spec->private_capsrc_nids[1] = 0x22;
14553 } else {
14554 spec->private_adc_nids[0] = 0x11;
14555 spec->private_adc_nids[1] = 0x08;
14556 spec->private_capsrc_nids[0] = 0x22;
14557 spec->private_capsrc_nids[1] = 0x23;
14558 }
14559 spec->adc_nids = spec->private_adc_nids;
14560 spec->capsrc_nids = spec->private_capsrc_nids;
14561 spec->num_adc_nids = 2;
14562 spec->dual_adc_switch = 1;
14563 snd_printdd("realtek: enabling dual ADC switchg (%02x:%02x)\n",
14564 spec->adc_nids[0], spec->adc_nids[1]);
14565 return 1;
14566 }
14567 return 0;
14568}
14569
Takashi Iwaid433a672010-09-20 15:11:54 +020014570/* different alc269-variants */
14571enum {
14572 ALC269_TYPE_NORMAL,
14573 ALC269_TYPE_ALC259,
14574 ALC269_TYPE_ALC271X,
14575};
14576
Kailang Yangf6a92242007-12-13 16:52:54 +010014577/*
14578 * BIOS auto configuration
14579 */
14580static int alc269_parse_auto_config(struct hda_codec *codec)
14581{
14582 struct alc_spec *spec = codec->spec;
Takashi Iwaicfb9fb52009-02-06 17:34:03 +010014583 int err;
Kailang Yangf6a92242007-12-13 16:52:54 +010014584 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
14585
14586 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
14587 alc269_ignore);
14588 if (err < 0)
14589 return err;
14590
14591 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
14592 if (err < 0)
14593 return err;
Takashi Iwaif3550d12010-09-20 15:09:03 +020014594 if (spec->codec_variant == ALC269_TYPE_NORMAL)
14595 err = alc269_auto_create_input_ctls(codec, &spec->autocfg);
14596 else
14597 err = alc_auto_create_input_ctls(codec, &spec->autocfg, 0,
14598 0x22, 0);
Kailang Yangf6a92242007-12-13 16:52:54 +010014599 if (err < 0)
14600 return err;
14601
14602 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
14603
Takashi Iwai757899a2010-07-30 10:48:14 +020014604 alc_auto_parse_digital(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014605
Takashi Iwai603c4012008-07-30 15:01:44 +020014606 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010014607 add_mixer(spec, spec->kctls.list);
Kailang Yangf6a92242007-12-13 16:52:54 +010014608
Takashi Iwaid433a672010-09-20 15:11:54 +020014609 if (spec->codec_variant != ALC269_TYPE_NORMAL) {
Kailang Yang84898e82010-02-04 14:16:14 +010014610 add_verb(spec, alc269vb_init_verbs);
Kailang Yang6227cdc2010-02-25 08:36:52 +010014611 alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21);
Kailang Yang84898e82010-02-04 14:16:14 +010014612 } else {
14613 add_verb(spec, alc269_init_verbs);
Kailang Yang6227cdc2010-02-25 08:36:52 +010014614 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Kailang Yang84898e82010-02-04 14:16:14 +010014615 }
14616
Kailang Yangf6a92242007-12-13 16:52:54 +010014617 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020014618 spec->input_mux = &spec->private_imux[0];
Takashi Iwai840b64c2010-07-13 22:49:01 +020014619
14620 if (!alc275_setup_dual_adc(codec))
14621 fillup_priv_adc_nids(codec, alc269_adc_candidates,
14622 sizeof(alc269_adc_candidates));
Takashi Iwai66946352010-03-29 17:21:45 +020014623
Takashi Iwaie01bf502008-08-21 16:25:07 +020014624 /* set default input source */
Takashi Iwai840b64c2010-07-13 22:49:01 +020014625 if (!spec->dual_adc_switch)
Takashi Iwai748cce42010-08-04 07:37:39 +020014626 select_or_unmute_capsrc(codec, spec->capsrc_nids[0],
14627 spec->input_mux->items[0].index);
Kailang Yangf6a92242007-12-13 16:52:54 +010014628
14629 err = alc_auto_add_mic_boost(codec);
14630 if (err < 0)
14631 return err;
14632
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010014633 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020014634 set_capture_mixer(codec);
Kailang Yangf53281e2008-07-18 12:36:43 +020014635
Kailang Yangf6a92242007-12-13 16:52:54 +010014636 return 1;
14637}
14638
Takashi Iwaie9af4f32009-08-29 23:23:08 +020014639#define alc269_auto_init_multi_out alc268_auto_init_multi_out
14640#define alc269_auto_init_hp_out alc268_auto_init_hp_out
Kailang Yangf6a92242007-12-13 16:52:54 +010014641#define alc269_auto_init_analog_input alc882_auto_init_analog_input
14642
14643
14644/* init callback for auto-configuration model -- overriding the default init */
14645static void alc269_auto_init(struct hda_codec *codec)
14646{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014647 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010014648 alc269_auto_init_multi_out(codec);
14649 alc269_auto_init_hp_out(codec);
14650 alc269_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020014651 alc_auto_init_digital(codec);
Kailang Yang9ad0e492010-09-14 23:22:00 +020014652 alc_init_jacks(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014653 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020014654 alc_inithook(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014655}
14656
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014657#ifdef SND_HDA_NEEDS_RESUME
14658static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
14659{
14660 int val = alc_read_coef_idx(codec, 0x04);
14661 if (power_up)
14662 val |= 1 << 11;
14663 else
14664 val &= ~(1 << 11);
14665 alc_write_coef_idx(codec, 0x04, val);
14666}
14667
Kailang Yang977ddd62010-09-15 10:02:29 +020014668#ifdef CONFIG_SND_HDA_POWER_SAVE
14669static int alc269_suspend(struct hda_codec *codec, pm_message_t state)
14670{
14671 struct alc_spec *spec = codec->spec;
Kailang Yang977ddd62010-09-15 10:02:29 +020014672
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014673 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017)
14674 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014675 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014676 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014677 msleep(150);
14678 }
14679
14680 alc_shutup(codec);
14681 if (spec && spec->power_hook)
14682 spec->power_hook(codec);
14683 return 0;
14684}
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014685#endif /* CONFIG_SND_HDA_POWER_SAVE */
14686
Kailang Yang977ddd62010-09-15 10:02:29 +020014687static int alc269_resume(struct hda_codec *codec)
14688{
Kailang Yang977ddd62010-09-15 10:02:29 +020014689 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014690 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014691 msleep(150);
14692 }
14693
14694 codec->patch_ops.init(codec);
14695
14696 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014697 alc269_toggle_power_output(codec, 1);
Kailang Yang977ddd62010-09-15 10:02:29 +020014698 msleep(200);
14699 }
14700
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014701 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018)
14702 alc269_toggle_power_output(codec, 1);
Kailang Yang977ddd62010-09-15 10:02:29 +020014703
14704 snd_hda_codec_resume_amp(codec);
14705 snd_hda_codec_resume_cache(codec);
Takashi Iwai9e5341b2010-09-21 09:57:06 +020014706 hda_call_check_power_status(codec, 0x01);
Kailang Yang977ddd62010-09-15 10:02:29 +020014707 return 0;
14708}
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014709#endif /* SND_HDA_NEEDS_RESUME */
Kailang Yang977ddd62010-09-15 10:02:29 +020014710
Takashi Iwaiff818c22010-04-12 08:59:25 +020014711enum {
14712 ALC269_FIXUP_SONY_VAIO,
David Henningsson145a9022010-09-16 10:07:53 +020014713 ALC269_FIXUP_DELL_M101Z,
Takashi Iwaiff818c22010-04-12 08:59:25 +020014714};
14715
Takashi Iwaiff818c22010-04-12 08:59:25 +020014716static const struct alc_fixup alc269_fixups[] = {
14717 [ALC269_FIXUP_SONY_VAIO] = {
Takashi Iwai73413b12010-08-30 09:39:57 +020014718 .verbs = (const struct hda_verb[]) {
14719 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
14720 {}
14721 }
Takashi Iwaiff818c22010-04-12 08:59:25 +020014722 },
David Henningsson145a9022010-09-16 10:07:53 +020014723 [ALC269_FIXUP_DELL_M101Z] = {
14724 .verbs = (const struct hda_verb[]) {
14725 /* Enables internal speaker */
14726 {0x20, AC_VERB_SET_COEF_INDEX, 13},
14727 {0x20, AC_VERB_SET_PROC_COEF, 0x4040},
14728 {}
14729 }
14730 },
Takashi Iwaiff818c22010-04-12 08:59:25 +020014731};
14732
14733static struct snd_pci_quirk alc269_fixup_tbl[] = {
Takashi Iwaiabdd8f52010-09-21 17:38:14 +020014734 SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
David Henningsson145a9022010-09-16 10:07:53 +020014735 SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
Takashi Iwaiff818c22010-04-12 08:59:25 +020014736 {}
14737};
14738
14739
Kailang Yangf6a92242007-12-13 16:52:54 +010014740/*
14741 * configuration and preset
14742 */
14743static const char *alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014744 [ALC269_BASIC] = "basic",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020014745 [ALC269_QUANTA_FL1] = "quanta",
Kailang Yang84898e82010-02-04 14:16:14 +010014746 [ALC269_AMIC] = "laptop-amic",
14747 [ALC269_DMIC] = "laptop-dmic",
Tony Vroon64154832008-11-06 15:08:49 +000014748 [ALC269_FUJITSU] = "fujitsu",
Takashi Iwai3d3792c2009-09-11 07:50:47 +020014749 [ALC269_LIFEBOOK] = "lifebook",
14750 [ALC269_AUTO] = "auto",
Kailang Yangf6a92242007-12-13 16:52:54 +010014751};
14752
14753static struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014754 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014755 SND_PCI_QUIRK(0x1025, 0x047c, "ACER ZGA", ALC271_ACER),
Kailang Yangf53281e2008-07-18 12:36:43 +020014756 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
Kailang Yang84898e82010-02-04 14:16:14 +010014757 ALC269_AMIC),
14758 SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC),
14759 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC),
14760 SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC),
14761 SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC),
14762 SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC),
14763 SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC),
14764 SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC),
14765 SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC),
14766 SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC),
14767 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82Jv", ALC269_AMIC),
14768 SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC),
14769 SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC),
14770 SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC),
14771 SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC),
14772 SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC),
14773 SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC),
14774 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC),
14775 SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC),
14776 SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC),
14777 SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC),
14778 SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC),
14779 SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC),
14780 SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC),
14781 SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC),
14782 SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC),
14783 SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC),
14784 SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC),
14785 SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC),
14786 SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC),
14787 SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC),
14788 SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC),
14789 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC),
14790 SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC),
14791 SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC),
14792 SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC),
14793 SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC),
Kailang Yangf53281e2008-07-18 12:36:43 +020014794 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
Kailang Yang84898e82010-02-04 14:16:14 +010014795 ALC269_DMIC),
Kailang Yang60db6b52008-08-26 13:13:00 +020014796 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
Kailang Yang84898e82010-02-04 14:16:14 +010014797 ALC269_DMIC),
14798 SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC),
14799 SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC),
Takashi Iwaiff818c22010-04-12 08:59:25 +020014800 SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_AUTO),
Tony Vroon64154832008-11-06 15:08:49 +000014801 SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
Kailang Yang61c2d2b2010-02-25 08:49:06 +010014802 SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC),
14803 SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
14804 SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_AMIC),
14805 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_AMIC),
14806 SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_DMIC),
14807 SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_DMIC),
Kailang Yangf6a92242007-12-13 16:52:54 +010014808 {}
14809};
14810
14811static struct alc_config_preset alc269_presets[] = {
14812 [ALC269_BASIC] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010014813 .mixers = { alc269_base_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010014814 .init_verbs = { alc269_init_verbs },
14815 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14816 .dac_nids = alc269_dac_nids,
14817 .hp_nid = 0x03,
14818 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14819 .channel_mode = alc269_modes,
14820 .input_mux = &alc269_capture_source,
14821 },
Kailang Yang60db6b52008-08-26 13:13:00 +020014822 [ALC269_QUANTA_FL1] = {
14823 .mixers = { alc269_quanta_fl1_mixer },
14824 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
14825 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14826 .dac_nids = alc269_dac_nids,
14827 .hp_nid = 0x03,
14828 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14829 .channel_mode = alc269_modes,
14830 .input_mux = &alc269_capture_source,
14831 .unsol_event = alc269_quanta_fl1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014832 .setup = alc269_quanta_fl1_setup,
Kailang Yang60db6b52008-08-26 13:13:00 +020014833 .init_hook = alc269_quanta_fl1_init_hook,
14834 },
Kailang Yang84898e82010-02-04 14:16:14 +010014835 [ALC269_AMIC] = {
14836 .mixers = { alc269_laptop_mixer },
14837 .cap_mixer = alc269_laptop_analog_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020014838 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014839 alc269_laptop_amic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020014840 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14841 .dac_nids = alc269_dac_nids,
14842 .hp_nid = 0x03,
14843 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14844 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010014845 .unsol_event = alc269_laptop_unsol_event,
14846 .setup = alc269_laptop_amic_setup,
14847 .init_hook = alc269_laptop_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020014848 },
Kailang Yang84898e82010-02-04 14:16:14 +010014849 [ALC269_DMIC] = {
14850 .mixers = { alc269_laptop_mixer },
14851 .cap_mixer = alc269_laptop_digital_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020014852 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014853 alc269_laptop_dmic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020014854 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14855 .dac_nids = alc269_dac_nids,
14856 .hp_nid = 0x03,
14857 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14858 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010014859 .unsol_event = alc269_laptop_unsol_event,
14860 .setup = alc269_laptop_dmic_setup,
14861 .init_hook = alc269_laptop_inithook,
14862 },
14863 [ALC269VB_AMIC] = {
14864 .mixers = { alc269vb_laptop_mixer },
14865 .cap_mixer = alc269vb_laptop_analog_capture_mixer,
14866 .init_verbs = { alc269vb_init_verbs,
14867 alc269vb_laptop_amic_init_verbs },
14868 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14869 .dac_nids = alc269_dac_nids,
14870 .hp_nid = 0x03,
14871 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14872 .channel_mode = alc269_modes,
14873 .unsol_event = alc269_laptop_unsol_event,
Kailang Yang226b1ec2010-04-09 11:01:20 +020014874 .setup = alc269vb_laptop_amic_setup,
Kailang Yang84898e82010-02-04 14:16:14 +010014875 .init_hook = alc269_laptop_inithook,
14876 },
14877 [ALC269VB_DMIC] = {
14878 .mixers = { alc269vb_laptop_mixer },
14879 .cap_mixer = alc269vb_laptop_digital_capture_mixer,
14880 .init_verbs = { alc269vb_init_verbs,
14881 alc269vb_laptop_dmic_init_verbs },
14882 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14883 .dac_nids = alc269_dac_nids,
14884 .hp_nid = 0x03,
14885 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14886 .channel_mode = alc269_modes,
14887 .unsol_event = alc269_laptop_unsol_event,
14888 .setup = alc269vb_laptop_dmic_setup,
14889 .init_hook = alc269_laptop_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020014890 },
Takashi Iwai26f5df22008-11-03 17:39:46 +010014891 [ALC269_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010014892 .mixers = { alc269_fujitsu_mixer },
Kailang Yang84898e82010-02-04 14:16:14 +010014893 .cap_mixer = alc269_laptop_digital_capture_mixer,
Takashi Iwai26f5df22008-11-03 17:39:46 +010014894 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014895 alc269_laptop_dmic_init_verbs },
Takashi Iwai26f5df22008-11-03 17:39:46 +010014896 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14897 .dac_nids = alc269_dac_nids,
14898 .hp_nid = 0x03,
14899 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14900 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010014901 .unsol_event = alc269_laptop_unsol_event,
14902 .setup = alc269_laptop_dmic_setup,
14903 .init_hook = alc269_laptop_inithook,
Takashi Iwai26f5df22008-11-03 17:39:46 +010014904 },
Tony Vroon64154832008-11-06 15:08:49 +000014905 [ALC269_LIFEBOOK] = {
14906 .mixers = { alc269_lifebook_mixer },
14907 .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
14908 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14909 .dac_nids = alc269_dac_nids,
14910 .hp_nid = 0x03,
14911 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14912 .channel_mode = alc269_modes,
14913 .input_mux = &alc269_capture_source,
14914 .unsol_event = alc269_lifebook_unsol_event,
14915 .init_hook = alc269_lifebook_init_hook,
14916 },
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014917 [ALC271_ACER] = {
14918 .mixers = { alc269_asus_mixer },
14919 .cap_mixer = alc269vb_laptop_digital_capture_mixer,
14920 .init_verbs = { alc269_init_verbs, alc271_acer_dmic_verbs },
14921 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14922 .dac_nids = alc269_dac_nids,
14923 .adc_nids = alc262_dmic_adc_nids,
14924 .num_adc_nids = ARRAY_SIZE(alc262_dmic_adc_nids),
14925 .capsrc_nids = alc262_dmic_capsrc_nids,
14926 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14927 .channel_mode = alc269_modes,
14928 .input_mux = &alc269_capture_source,
14929 .dig_out_nid = ALC880_DIGOUT_NID,
14930 .unsol_event = alc_sku_unsol_event,
14931 .setup = alc269vb_laptop_dmic_setup,
14932 .init_hook = alc_inithook,
14933 },
Kailang Yangf6a92242007-12-13 16:52:54 +010014934};
14935
Kailang Yang977ddd62010-09-15 10:02:29 +020014936static int alc269_fill_coef(struct hda_codec *codec)
14937{
14938 int val;
14939
14940 if ((alc_read_coef_idx(codec, 0) & 0x00ff) < 0x015) {
14941 alc_write_coef_idx(codec, 0xf, 0x960b);
14942 alc_write_coef_idx(codec, 0xe, 0x8817);
14943 }
14944
14945 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x016) {
14946 alc_write_coef_idx(codec, 0xf, 0x960b);
14947 alc_write_coef_idx(codec, 0xe, 0x8814);
14948 }
14949
14950 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
14951 val = alc_read_coef_idx(codec, 0x04);
14952 /* Power up output pin */
14953 alc_write_coef_idx(codec, 0x04, val | (1<<11));
14954 }
14955
14956 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
14957 val = alc_read_coef_idx(codec, 0xd);
14958 if ((val & 0x0c00) >> 10 != 0x1) {
14959 /* Capless ramp up clock control */
14960 alc_write_coef_idx(codec, 0xd, val | 1<<10);
14961 }
14962 val = alc_read_coef_idx(codec, 0x17);
14963 if ((val & 0x01c0) >> 6 != 0x4) {
14964 /* Class D power on reset */
14965 alc_write_coef_idx(codec, 0x17, val | 1<<7);
14966 }
14967 }
14968 return 0;
14969}
14970
Kailang Yangf6a92242007-12-13 16:52:54 +010014971static int patch_alc269(struct hda_codec *codec)
14972{
14973 struct alc_spec *spec;
14974 int board_config;
14975 int err;
14976
14977 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
14978 if (spec == NULL)
14979 return -ENOMEM;
14980
14981 codec->spec = spec;
14982
Kailang Yangda00c242010-03-19 11:23:45 +010014983 alc_auto_parse_customize_define(codec);
14984
Kailang Yang274693f2009-12-03 10:07:50 +010014985 if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){
Kailang Yangc027ddc2010-03-19 11:33:06 +010014986 if (codec->bus->pci->subsystem_vendor == 0x1025 &&
Takashi Iwaid433a672010-09-20 15:11:54 +020014987 spec->cdefine.platform_type == 1) {
Kailang Yangc027ddc2010-03-19 11:33:06 +010014988 alc_codec_rename(codec, "ALC271X");
Takashi Iwaid433a672010-09-20 15:11:54 +020014989 spec->codec_variant = ALC269_TYPE_ALC271X;
14990 } else {
Kailang Yangc027ddc2010-03-19 11:33:06 +010014991 alc_codec_rename(codec, "ALC259");
Takashi Iwaid433a672010-09-20 15:11:54 +020014992 spec->codec_variant = ALC269_TYPE_ALC259;
14993 }
Kailang Yangc027ddc2010-03-19 11:33:06 +010014994 } else
14995 alc_fix_pll_init(codec, 0x20, 0x04, 15);
Kailang Yang274693f2009-12-03 10:07:50 +010014996
Kailang Yang977ddd62010-09-15 10:02:29 +020014997 alc269_fill_coef(codec);
14998
Kailang Yangf6a92242007-12-13 16:52:54 +010014999 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
15000 alc269_models,
15001 alc269_cfg_tbl);
15002
15003 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020015004 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
15005 codec->chip_name);
Kailang Yangf6a92242007-12-13 16:52:54 +010015006 board_config = ALC269_AUTO;
15007 }
15008
Takashi Iwaiff818c22010-04-12 08:59:25 +020015009 if (board_config == ALC269_AUTO)
15010 alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 1);
15011
Kailang Yangf6a92242007-12-13 16:52:54 +010015012 if (board_config == ALC269_AUTO) {
15013 /* automatic parse from the BIOS config */
15014 err = alc269_parse_auto_config(codec);
15015 if (err < 0) {
15016 alc_free(codec);
15017 return err;
15018 } else if (!err) {
15019 printk(KERN_INFO
15020 "hda_codec: Cannot set up configuration "
15021 "from BIOS. Using base mode...\n");
15022 board_config = ALC269_BASIC;
15023 }
15024 }
15025
Takashi Iwaidc1eae22010-07-29 15:30:02 +020015026 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020015027 err = snd_hda_attach_beep_device(codec, 0x1);
15028 if (err < 0) {
15029 alc_free(codec);
15030 return err;
15031 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090015032 }
15033
Kailang Yangf6a92242007-12-13 16:52:54 +010015034 if (board_config != ALC269_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020015035 setup_preset(codec, &alc269_presets[board_config]);
Kailang Yangf6a92242007-12-13 16:52:54 +010015036
Kailang Yang84898e82010-02-04 14:16:14 +010015037 if (board_config == ALC269_QUANTA_FL1) {
Takashi Iwaif03d3112009-03-05 14:18:16 +010015038 /* Due to a hardware problem on Lenovo Ideadpad, we need to
15039 * fix the sample rate of analog I/O to 44.1kHz
15040 */
15041 spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
15042 spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
Takashi Iwai840b64c2010-07-13 22:49:01 +020015043 } else if (spec->dual_adc_switch) {
15044 spec->stream_analog_playback = &alc269_pcm_analog_playback;
15045 /* switch ADC dynamically */
15046 spec->stream_analog_capture = &dualmic_pcm_analog_capture;
Takashi Iwaif03d3112009-03-05 14:18:16 +010015047 } else {
15048 spec->stream_analog_playback = &alc269_pcm_analog_playback;
15049 spec->stream_analog_capture = &alc269_pcm_analog_capture;
15050 }
Kailang Yangf6a92242007-12-13 16:52:54 +010015051 spec->stream_digital_playback = &alc269_pcm_digital_playback;
15052 spec->stream_digital_capture = &alc269_pcm_digital_capture;
15053
Takashi Iwai66946352010-03-29 17:21:45 +020015054 if (!spec->adc_nids) { /* wasn't filled automatically? use default */
Takashi Iwaid433a672010-09-20 15:11:54 +020015055 if (spec->codec_variant != ALC269_TYPE_NORMAL) {
Takashi Iwai66946352010-03-29 17:21:45 +020015056 spec->adc_nids = alc269_adc_nids;
15057 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
15058 spec->capsrc_nids = alc269_capsrc_nids;
15059 } else {
15060 spec->adc_nids = alc269vb_adc_nids;
15061 spec->num_adc_nids = ARRAY_SIZE(alc269vb_adc_nids);
15062 spec->capsrc_nids = alc269vb_capsrc_nids;
15063 }
Kailang Yang84898e82010-02-04 14:16:14 +010015064 }
15065
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015066 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020015067 set_capture_mixer(codec);
Takashi Iwaidc1eae22010-07-29 15:30:02 +020015068 if (has_cdefine_beep(codec))
Kailang Yangda00c242010-03-19 11:23:45 +010015069 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Kailang Yangf6a92242007-12-13 16:52:54 +010015070
Takashi Iwaiff818c22010-04-12 08:59:25 +020015071 if (board_config == ALC269_AUTO)
15072 alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 0);
15073
Takashi Iwai100d5eb2009-08-10 11:55:51 +020015074 spec->vmaster_nid = 0x02;
15075
Kailang Yangf6a92242007-12-13 16:52:54 +010015076 codec->patch_ops = alc_patch_ops;
Kailang Yang977ddd62010-09-15 10:02:29 +020015077#ifdef CONFIG_SND_HDA_POWER_SAVE
15078 codec->patch_ops.suspend = alc269_suspend;
15079#endif
15080#ifdef SND_HDA_NEEDS_RESUME
15081 codec->patch_ops.resume = alc269_resume;
15082#endif
Kailang Yangf6a92242007-12-13 16:52:54 +010015083 if (board_config == ALC269_AUTO)
15084 spec->init_hook = alc269_auto_init;
15085#ifdef CONFIG_SND_HDA_POWER_SAVE
15086 if (!spec->loopback.amplist)
15087 spec->loopback.amplist = alc269_loopbacks;
Takashi Iwaiad358792010-03-30 18:00:59 +020015088 if (alc269_mic2_for_mute_led(codec))
15089 codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps;
Kailang Yangf6a92242007-12-13 16:52:54 +010015090#endif
15091
15092 return 0;
15093}
15094
15095/*
Kailang Yangdf694da2005-12-05 19:42:22 +010015096 * ALC861 channel source setting (2/6 channel selection for 3-stack)
15097 */
15098
15099/*
15100 * set the path ways for 2 channel output
15101 * need to set the codec line out and mic 1 pin widgets to inputs
15102 */
15103static struct hda_verb alc861_threestack_ch2_init[] = {
15104 /* set pin widget 1Ah (line in) for input */
15105 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015106 /* set pin widget 18h (mic1/2) for input, for mic also enable
15107 * the vref
15108 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015109 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15110
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015111 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
15112#if 0
15113 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
15114 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
15115#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010015116 { } /* end */
15117};
15118/*
15119 * 6ch mode
15120 * need to set the codec line out and mic 1 pin widgets to outputs
15121 */
15122static struct hda_verb alc861_threestack_ch6_init[] = {
15123 /* set pin widget 1Ah (line in) for output (Back Surround)*/
15124 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15125 /* set pin widget 18h (mic1) for output (CLFE)*/
15126 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15127
15128 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015129 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015130
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015131 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
15132#if 0
15133 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
15134 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
15135#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010015136 { } /* end */
15137};
15138
15139static struct hda_channel_mode alc861_threestack_modes[2] = {
15140 { 2, alc861_threestack_ch2_init },
15141 { 6, alc861_threestack_ch6_init },
15142};
Takashi Iwai22309c32006-08-09 16:57:28 +020015143/* Set mic1 as input and unmute the mixer */
15144static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
15145 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15146 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
15147 { } /* end */
15148};
15149/* Set mic1 as output and mute mixer */
15150static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
15151 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15152 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
15153 { } /* end */
15154};
15155
15156static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
15157 { 2, alc861_uniwill_m31_ch2_init },
15158 { 4, alc861_uniwill_m31_ch4_init },
15159};
Kailang Yangdf694da2005-12-05 19:42:22 +010015160
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015161/* Set mic1 and line-in as input and unmute the mixer */
15162static struct hda_verb alc861_asus_ch2_init[] = {
15163 /* set pin widget 1Ah (line in) for input */
15164 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015165 /* set pin widget 18h (mic1/2) for input, for mic also enable
15166 * the vref
15167 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015168 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15169
15170 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
15171#if 0
15172 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
15173 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
15174#endif
15175 { } /* end */
15176};
15177/* Set mic1 nad line-in as output and mute mixer */
15178static struct hda_verb alc861_asus_ch6_init[] = {
15179 /* set pin widget 1Ah (line in) for output (Back Surround)*/
15180 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15181 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
15182 /* set pin widget 18h (mic1) for output (CLFE)*/
15183 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15184 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
15185 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
15186 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
15187
15188 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
15189#if 0
15190 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
15191 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
15192#endif
15193 { } /* end */
15194};
15195
15196static struct hda_channel_mode alc861_asus_modes[2] = {
15197 { 2, alc861_asus_ch2_init },
15198 { 6, alc861_asus_ch6_init },
15199};
15200
Kailang Yangdf694da2005-12-05 19:42:22 +010015201/* patch-ALC861 */
15202
15203static struct snd_kcontrol_new alc861_base_mixer[] = {
15204 /* output mixer control */
15205 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15206 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15207 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15208 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15209 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
15210
15211 /*Input mixer control */
15212 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15213 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
15214 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15215 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15216 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15217 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15218 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15219 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15220 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
15221 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015222
Kailang Yangdf694da2005-12-05 19:42:22 +010015223 { } /* end */
15224};
15225
15226static struct snd_kcontrol_new alc861_3ST_mixer[] = {
15227 /* output mixer control */
15228 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15229 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15230 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15231 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15232 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
15233
15234 /* Input mixer control */
15235 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15236 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
15237 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15238 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15239 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15240 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15241 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15242 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15243 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
15244 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015245
Kailang Yangdf694da2005-12-05 19:42:22 +010015246 {
15247 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15248 .name = "Channel Mode",
15249 .info = alc_ch_mode_info,
15250 .get = alc_ch_mode_get,
15251 .put = alc_ch_mode_put,
15252 .private_value = ARRAY_SIZE(alc861_threestack_modes),
15253 },
15254 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015255};
15256
Takashi Iwaid1d985f2006-11-23 19:27:12 +010015257static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015258 /* output mixer control */
15259 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15260 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15261 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020015262
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015263 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015264};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015265
Takashi Iwai22309c32006-08-09 16:57:28 +020015266static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
15267 /* output mixer control */
15268 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15269 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15270 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15271 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15272 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
15273
15274 /* Input mixer control */
15275 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15276 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
15277 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15278 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15279 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15280 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15281 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15282 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15283 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
15284 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015285
Takashi Iwai22309c32006-08-09 16:57:28 +020015286 {
15287 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15288 .name = "Channel Mode",
15289 .info = alc_ch_mode_info,
15290 .get = alc_ch_mode_get,
15291 .put = alc_ch_mode_put,
15292 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
15293 },
15294 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015295};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015296
15297static struct snd_kcontrol_new alc861_asus_mixer[] = {
15298 /* output mixer control */
15299 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15300 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15301 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15302 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15303 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
15304
15305 /* Input mixer control */
15306 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15307 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
15308 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15309 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15310 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15311 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15312 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15313 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15314 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015315 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
15316
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015317 {
15318 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15319 .name = "Channel Mode",
15320 .info = alc_ch_mode_info,
15321 .get = alc_ch_mode_get,
15322 .put = alc_ch_mode_put,
15323 .private_value = ARRAY_SIZE(alc861_asus_modes),
15324 },
15325 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015326};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015327
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015328/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010015329static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015330 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15331 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015332 { }
15333};
15334
Kailang Yangdf694da2005-12-05 19:42:22 +010015335/*
15336 * generic initialization of ADC, input mixers and output mixers
15337 */
15338static struct hda_verb alc861_base_init_verbs[] = {
15339 /*
15340 * Unmute ADC0 and set the default input to mic-in
15341 */
15342 /* port-A for surround (rear panel) */
15343 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15344 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
15345 /* port-B for mic-in (rear panel) with vref */
15346 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15347 /* port-C for line-in (rear panel) */
15348 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15349 /* port-D for Front */
15350 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15351 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15352 /* port-E for HP out (front panel) */
15353 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
15354 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015355 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015356 /* port-F for mic-in (front panel) with vref */
15357 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15358 /* port-G for CLFE (rear panel) */
15359 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15360 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
15361 /* port-H for side (rear panel) */
15362 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15363 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
15364 /* CD-in */
15365 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15366 /* route front mic to ADC1*/
15367 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15368 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015369
Kailang Yangdf694da2005-12-05 19:42:22 +010015370 /* Unmute DAC0~3 & spdif out*/
15371 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15372 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15373 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15374 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15375 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015376
Kailang Yangdf694da2005-12-05 19:42:22 +010015377 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15378 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15379 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15380 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15381 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015382
Kailang Yangdf694da2005-12-05 19:42:22 +010015383 /* Unmute Stereo Mixer 15 */
15384 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15385 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15386 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015387 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015388
15389 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15390 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15391 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15392 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15393 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15394 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15395 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15396 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015397 /* hp used DAC 3 (Front) */
15398 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015399 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15400
15401 { }
15402};
15403
15404static struct hda_verb alc861_threestack_init_verbs[] = {
15405 /*
15406 * Unmute ADC0 and set the default input to mic-in
15407 */
15408 /* port-A for surround (rear panel) */
15409 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15410 /* port-B for mic-in (rear panel) with vref */
15411 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15412 /* port-C for line-in (rear panel) */
15413 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15414 /* port-D for Front */
15415 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15416 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15417 /* port-E for HP out (front panel) */
15418 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
15419 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015420 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015421 /* port-F for mic-in (front panel) with vref */
15422 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15423 /* port-G for CLFE (rear panel) */
15424 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15425 /* port-H for side (rear panel) */
15426 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15427 /* CD-in */
15428 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15429 /* route front mic to ADC1*/
15430 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15431 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15432 /* Unmute DAC0~3 & spdif out*/
15433 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15434 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15435 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15436 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15437 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015438
Kailang Yangdf694da2005-12-05 19:42:22 +010015439 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15440 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15441 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15442 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15443 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015444
Kailang Yangdf694da2005-12-05 19:42:22 +010015445 /* Unmute Stereo Mixer 15 */
15446 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15447 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15448 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015449 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015450
15451 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15452 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15453 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15454 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15455 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15456 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15457 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15458 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015459 /* hp used DAC 3 (Front) */
15460 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015461 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15462 { }
15463};
Takashi Iwai22309c32006-08-09 16:57:28 +020015464
15465static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
15466 /*
15467 * Unmute ADC0 and set the default input to mic-in
15468 */
15469 /* port-A for surround (rear panel) */
15470 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15471 /* port-B for mic-in (rear panel) with vref */
15472 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15473 /* port-C for line-in (rear panel) */
15474 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15475 /* port-D for Front */
15476 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15477 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15478 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015479 /* this has to be set to VREF80 */
15480 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015481 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015482 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015483 /* port-F for mic-in (front panel) with vref */
15484 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15485 /* port-G for CLFE (rear panel) */
15486 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15487 /* port-H for side (rear panel) */
15488 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15489 /* CD-in */
15490 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15491 /* route front mic to ADC1*/
15492 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15493 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15494 /* Unmute DAC0~3 & spdif out*/
15495 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15496 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15497 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15498 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15499 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015500
Takashi Iwai22309c32006-08-09 16:57:28 +020015501 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15502 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15503 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15504 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15505 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015506
Takashi Iwai22309c32006-08-09 16:57:28 +020015507 /* Unmute Stereo Mixer 15 */
15508 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15509 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15510 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015511 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020015512
15513 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15514 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15515 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15516 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15517 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15518 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15519 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15520 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015521 /* hp used DAC 3 (Front) */
15522 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020015523 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15524 { }
15525};
15526
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015527static struct hda_verb alc861_asus_init_verbs[] = {
15528 /*
15529 * Unmute ADC0 and set the default input to mic-in
15530 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015531 /* port-A for surround (rear panel)
15532 * according to codec#0 this is the HP jack
15533 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015534 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
15535 /* route front PCM to HP */
15536 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
15537 /* port-B for mic-in (rear panel) with vref */
15538 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15539 /* port-C for line-in (rear panel) */
15540 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15541 /* port-D for Front */
15542 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15543 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15544 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015545 /* this has to be set to VREF80 */
15546 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015547 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015548 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015549 /* port-F for mic-in (front panel) with vref */
15550 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15551 /* port-G for CLFE (rear panel) */
15552 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15553 /* port-H for side (rear panel) */
15554 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15555 /* CD-in */
15556 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15557 /* route front mic to ADC1*/
15558 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15559 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15560 /* Unmute DAC0~3 & spdif out*/
15561 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15562 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15563 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15564 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15565 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15566 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15567 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15568 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15569 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15570 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015571
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015572 /* Unmute Stereo Mixer 15 */
15573 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15574 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15575 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015576 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015577
15578 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15579 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15580 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15581 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15582 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15583 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15584 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15585 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015586 /* hp used DAC 3 (Front) */
15587 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015588 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15589 { }
15590};
15591
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015592/* additional init verbs for ASUS laptops */
15593static struct hda_verb alc861_asus_laptop_init_verbs[] = {
15594 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
15595 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
15596 { }
15597};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015598
Kailang Yangdf694da2005-12-05 19:42:22 +010015599/*
15600 * generic initialization of ADC, input mixers and output mixers
15601 */
15602static struct hda_verb alc861_auto_init_verbs[] = {
15603 /*
15604 * Unmute ADC0 and set the default input to mic-in
15605 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015606 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010015607 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015608
Kailang Yangdf694da2005-12-05 19:42:22 +010015609 /* Unmute DAC0~3 & spdif out*/
15610 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15611 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15612 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15613 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15614 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015615
Kailang Yangdf694da2005-12-05 19:42:22 +010015616 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15617 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15618 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15619 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15620 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015621
Kailang Yangdf694da2005-12-05 19:42:22 +010015622 /* Unmute Stereo Mixer 15 */
15623 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15624 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15625 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15626 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
15627
Takashi Iwai1c209302009-07-22 15:17:45 +020015628 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15629 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15630 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15631 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15632 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15633 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15634 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15635 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015636
15637 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15638 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020015639 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15640 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015641 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15642 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020015643 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15644 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015645
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015646 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015647
15648 { }
15649};
15650
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015651static struct hda_verb alc861_toshiba_init_verbs[] = {
15652 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015653
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015654 { }
15655};
15656
15657/* toggle speaker-output according to the hp-jack state */
15658static void alc861_toshiba_automute(struct hda_codec *codec)
15659{
Wu Fengguang864f92b2009-11-18 12:38:02 +080015660 unsigned int present = snd_hda_jack_detect(codec, 0x0f);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015661
Takashi Iwai47fd8302007-08-10 17:11:07 +020015662 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
15663 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
15664 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
15665 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015666}
15667
15668static void alc861_toshiba_unsol_event(struct hda_codec *codec,
15669 unsigned int res)
15670{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015671 if ((res >> 26) == ALC880_HP_EVENT)
15672 alc861_toshiba_automute(codec);
15673}
15674
Sasha Alexandrdef319f2009-06-16 16:00:15 -040015675/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015676#define alc861_pcm_analog_playback alc880_pcm_analog_playback
15677#define alc861_pcm_analog_capture alc880_pcm_analog_capture
15678#define alc861_pcm_digital_playback alc880_pcm_digital_playback
15679#define alc861_pcm_digital_capture alc880_pcm_digital_capture
15680
15681
15682#define ALC861_DIGOUT_NID 0x07
15683
15684static struct hda_channel_mode alc861_8ch_modes[1] = {
15685 { 8, NULL }
15686};
15687
15688static hda_nid_t alc861_dac_nids[4] = {
15689 /* front, surround, clfe, side */
15690 0x03, 0x06, 0x05, 0x04
15691};
15692
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015693static hda_nid_t alc660_dac_nids[3] = {
15694 /* front, clfe, surround */
15695 0x03, 0x05, 0x06
15696};
15697
Kailang Yangdf694da2005-12-05 19:42:22 +010015698static hda_nid_t alc861_adc_nids[1] = {
15699 /* ADC0-2 */
15700 0x08,
15701};
15702
15703static struct hda_input_mux alc861_capture_source = {
15704 .num_items = 5,
15705 .items = {
15706 { "Mic", 0x0 },
15707 { "Front Mic", 0x3 },
15708 { "Line", 0x1 },
15709 { "CD", 0x4 },
15710 { "Mixer", 0x5 },
15711 },
15712};
15713
Takashi Iwai1c209302009-07-22 15:17:45 +020015714static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
15715{
15716 struct alc_spec *spec = codec->spec;
15717 hda_nid_t mix, srcs[5];
15718 int i, j, num;
15719
15720 if (snd_hda_get_connections(codec, pin, &mix, 1) != 1)
15721 return 0;
15722 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
15723 if (num < 0)
15724 return 0;
15725 for (i = 0; i < num; i++) {
15726 unsigned int type;
Takashi Iwaia22d5432009-07-27 12:54:26 +020015727 type = get_wcaps_type(get_wcaps(codec, srcs[i]));
Takashi Iwai1c209302009-07-22 15:17:45 +020015728 if (type != AC_WID_AUD_OUT)
15729 continue;
15730 for (j = 0; j < spec->multiout.num_dacs; j++)
15731 if (spec->multiout.dac_nids[j] == srcs[i])
15732 break;
15733 if (j >= spec->multiout.num_dacs)
15734 return srcs[i];
15735 }
15736 return 0;
15737}
15738
Kailang Yangdf694da2005-12-05 19:42:22 +010015739/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwai1c209302009-07-22 15:17:45 +020015740static int alc861_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015741 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010015742{
Takashi Iwai1c209302009-07-22 15:17:45 +020015743 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015744 int i;
Takashi Iwai1c209302009-07-22 15:17:45 +020015745 hda_nid_t nid, dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010015746
15747 spec->multiout.dac_nids = spec->private_dac_nids;
15748 for (i = 0; i < cfg->line_outs; i++) {
15749 nid = cfg->line_out_pins[i];
Takashi Iwai1c209302009-07-22 15:17:45 +020015750 dac = alc861_look_for_dac(codec, nid);
15751 if (!dac)
15752 continue;
15753 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010015754 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015755 return 0;
15756}
15757
Takashi Iwai1c209302009-07-22 15:17:45 +020015758static int alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
15759 hda_nid_t nid, unsigned int chs)
Kailang Yangdf694da2005-12-05 19:42:22 +010015760{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015761 return add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai1c209302009-07-22 15:17:45 +020015762 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
15763}
15764
15765/* add playback controls from the parsed DAC table */
15766static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
15767 const struct auto_pin_cfg *cfg)
15768{
15769 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015770 static const char *chname[4] = {
15771 "Front", "Surround", NULL /*CLFE*/, "Side"
15772 };
Kailang Yangdf694da2005-12-05 19:42:22 +010015773 hda_nid_t nid;
Takashi Iwai1c209302009-07-22 15:17:45 +020015774 int i, err;
15775
15776 if (cfg->line_outs == 1) {
15777 const char *pfx = NULL;
15778 if (!cfg->hp_outs)
15779 pfx = "Master";
15780 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
15781 pfx = "Speaker";
15782 if (pfx) {
15783 nid = spec->multiout.dac_nids[0];
15784 return alc861_create_out_sw(codec, pfx, nid, 3);
15785 }
15786 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015787
15788 for (i = 0; i < cfg->line_outs; i++) {
15789 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015790 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010015791 continue;
Takashi Iwai1c209302009-07-22 15:17:45 +020015792 if (i == 2) {
Kailang Yangdf694da2005-12-05 19:42:22 +010015793 /* Center/LFE */
Takashi Iwai1c209302009-07-22 15:17:45 +020015794 err = alc861_create_out_sw(codec, "Center", nid, 1);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015795 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015796 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015797 err = alc861_create_out_sw(codec, "LFE", nid, 2);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015798 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015799 return err;
15800 } else {
Takashi Iwai1c209302009-07-22 15:17:45 +020015801 err = alc861_create_out_sw(codec, chname[i], nid, 3);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015802 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015803 return err;
15804 }
15805 }
15806 return 0;
15807}
15808
Takashi Iwai1c209302009-07-22 15:17:45 +020015809static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010015810{
Takashi Iwai1c209302009-07-22 15:17:45 +020015811 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015812 int err;
15813 hda_nid_t nid;
15814
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015815 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010015816 return 0;
15817
15818 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
Takashi Iwai1c209302009-07-22 15:17:45 +020015819 nid = alc861_look_for_dac(codec, pin);
15820 if (nid) {
15821 err = alc861_create_out_sw(codec, "Headphone", nid, 3);
15822 if (err < 0)
15823 return err;
15824 spec->multiout.hp_nid = nid;
15825 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015826 }
15827 return 0;
15828}
15829
15830/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020015831static int alc861_auto_create_input_ctls(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015832 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010015833{
Takashi Iwai05f5f472009-08-25 13:10:18 +020015834 return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x08, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010015835}
15836
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015837static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
15838 hda_nid_t nid,
Takashi Iwai1c209302009-07-22 15:17:45 +020015839 int pin_type, hda_nid_t dac)
Kailang Yangdf694da2005-12-05 19:42:22 +010015840{
Takashi Iwai1c209302009-07-22 15:17:45 +020015841 hda_nid_t mix, srcs[5];
15842 int i, num;
15843
Jacek Luczak564c5be2008-05-03 18:41:23 +020015844 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
15845 pin_type);
Takashi Iwai1c209302009-07-22 15:17:45 +020015846 snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Jacek Luczak564c5be2008-05-03 18:41:23 +020015847 AMP_OUT_UNMUTE);
Takashi Iwai1c209302009-07-22 15:17:45 +020015848 if (snd_hda_get_connections(codec, nid, &mix, 1) != 1)
15849 return;
15850 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
15851 if (num < 0)
15852 return;
15853 for (i = 0; i < num; i++) {
15854 unsigned int mute;
15855 if (srcs[i] == dac || srcs[i] == 0x15)
15856 mute = AMP_IN_UNMUTE(i);
15857 else
15858 mute = AMP_IN_MUTE(i);
15859 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15860 mute);
15861 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015862}
15863
15864static void alc861_auto_init_multi_out(struct hda_codec *codec)
15865{
15866 struct alc_spec *spec = codec->spec;
15867 int i;
15868
15869 for (i = 0; i < spec->autocfg.line_outs; i++) {
15870 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015871 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010015872 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015873 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015874 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010015875 }
15876}
15877
15878static void alc861_auto_init_hp_out(struct hda_codec *codec)
15879{
15880 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015881
Takashi Iwai15870f02009-10-05 08:25:13 +020015882 if (spec->autocfg.hp_outs)
15883 alc861_auto_set_output_and_unmute(codec,
15884 spec->autocfg.hp_pins[0],
15885 PIN_HP,
Takashi Iwai1c209302009-07-22 15:17:45 +020015886 spec->multiout.hp_nid);
Takashi Iwai15870f02009-10-05 08:25:13 +020015887 if (spec->autocfg.speaker_outs)
15888 alc861_auto_set_output_and_unmute(codec,
15889 spec->autocfg.speaker_pins[0],
15890 PIN_OUT,
Takashi Iwai1c209302009-07-22 15:17:45 +020015891 spec->multiout.dac_nids[0]);
Kailang Yangdf694da2005-12-05 19:42:22 +010015892}
15893
15894static void alc861_auto_init_analog_input(struct hda_codec *codec)
15895{
15896 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020015897 struct auto_pin_cfg *cfg = &spec->autocfg;
Kailang Yangdf694da2005-12-05 19:42:22 +010015898 int i;
15899
Takashi Iwai66ceeb62010-08-30 13:05:52 +020015900 for (i = 0; i < cfg->num_inputs; i++) {
15901 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai23f0c042009-02-26 13:03:58 +010015902 if (nid >= 0x0c && nid <= 0x11)
Takashi Iwai30ea0982010-09-16 18:47:56 +020015903 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Kailang Yangdf694da2005-12-05 19:42:22 +010015904 }
15905}
15906
15907/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015908/* return 1 if successful, 0 if the proper config is not found,
15909 * or a negative error code
15910 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015911static int alc861_parse_auto_config(struct hda_codec *codec)
15912{
15913 struct alc_spec *spec = codec->spec;
15914 int err;
15915 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
15916
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015917 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
15918 alc861_ignore);
15919 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015920 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015921 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010015922 return 0; /* can't find valid BIOS pin config */
15923
Takashi Iwai1c209302009-07-22 15:17:45 +020015924 err = alc861_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015925 if (err < 0)
15926 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015927 err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015928 if (err < 0)
15929 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015930 err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015931 if (err < 0)
15932 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020015933 err = alc861_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015934 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015935 return err;
15936
15937 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
15938
Takashi Iwai757899a2010-07-30 10:48:14 +020015939 alc_auto_parse_digital(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015940
Takashi Iwai603c4012008-07-30 15:01:44 +020015941 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010015942 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010015943
Takashi Iwaid88897e2008-10-31 15:01:37 +010015944 add_verb(spec, alc861_auto_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +010015945
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020015946 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020015947 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010015948
15949 spec->adc_nids = alc861_adc_nids;
15950 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
Takashi Iwaib59bdf32009-08-11 09:47:30 +020015951 set_capture_mixer(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015952
Kailang Yang6227cdc2010-02-25 08:36:52 +010015953 alc_ssid_check(codec, 0x0e, 0x0f, 0x0b, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020015954
Kailang Yangdf694da2005-12-05 19:42:22 +010015955 return 1;
15956}
15957
Takashi Iwaiae6b8132006-03-03 16:47:17 +010015958/* additional initialization for auto-configuration model */
15959static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010015960{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015961 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015962 alc861_auto_init_multi_out(codec);
15963 alc861_auto_init_hp_out(codec);
15964 alc861_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020015965 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015966 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020015967 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015968}
15969
Takashi Iwaicb53c622007-08-10 17:21:45 +020015970#ifdef CONFIG_SND_HDA_POWER_SAVE
15971static struct hda_amp_list alc861_loopbacks[] = {
15972 { 0x15, HDA_INPUT, 0 },
15973 { 0x15, HDA_INPUT, 1 },
15974 { 0x15, HDA_INPUT, 2 },
15975 { 0x15, HDA_INPUT, 3 },
15976 { } /* end */
15977};
15978#endif
15979
Kailang Yangdf694da2005-12-05 19:42:22 +010015980
15981/*
15982 * configuration and preset
15983 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015984static const char *alc861_models[ALC861_MODEL_LAST] = {
15985 [ALC861_3ST] = "3stack",
15986 [ALC660_3ST] = "3stack-660",
15987 [ALC861_3ST_DIG] = "3stack-dig",
15988 [ALC861_6ST_DIG] = "6stack-dig",
15989 [ALC861_UNIWILL_M31] = "uniwill-m31",
15990 [ALC861_TOSHIBA] = "toshiba",
15991 [ALC861_ASUS] = "asus",
15992 [ALC861_ASUS_LAPTOP] = "asus-laptop",
15993 [ALC861_AUTO] = "auto",
15994};
15995
15996static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010015997 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015998 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
15999 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
16000 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016001 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020016002 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010016003 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020016004 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
16005 * Any other models that need this preset?
16006 */
16007 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020016008 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
16009 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016010 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
16011 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
16012 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
16013 /* FIXME: the below seems conflict */
16014 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
16015 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
16016 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010016017 {}
16018};
16019
16020static struct alc_config_preset alc861_presets[] = {
16021 [ALC861_3ST] = {
16022 .mixers = { alc861_3ST_mixer },
16023 .init_verbs = { alc861_threestack_init_verbs },
16024 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16025 .dac_nids = alc861_dac_nids,
16026 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
16027 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020016028 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010016029 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16030 .adc_nids = alc861_adc_nids,
16031 .input_mux = &alc861_capture_source,
16032 },
16033 [ALC861_3ST_DIG] = {
16034 .mixers = { alc861_base_mixer },
16035 .init_verbs = { alc861_threestack_init_verbs },
16036 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16037 .dac_nids = alc861_dac_nids,
16038 .dig_out_nid = ALC861_DIGOUT_NID,
16039 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
16040 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020016041 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010016042 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16043 .adc_nids = alc861_adc_nids,
16044 .input_mux = &alc861_capture_source,
16045 },
16046 [ALC861_6ST_DIG] = {
16047 .mixers = { alc861_base_mixer },
16048 .init_verbs = { alc861_base_init_verbs },
16049 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16050 .dac_nids = alc861_dac_nids,
16051 .dig_out_nid = ALC861_DIGOUT_NID,
16052 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
16053 .channel_mode = alc861_8ch_modes,
16054 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16055 .adc_nids = alc861_adc_nids,
16056 .input_mux = &alc861_capture_source,
16057 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016058 [ALC660_3ST] = {
16059 .mixers = { alc861_3ST_mixer },
16060 .init_verbs = { alc861_threestack_init_verbs },
16061 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
16062 .dac_nids = alc660_dac_nids,
16063 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
16064 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020016065 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016066 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16067 .adc_nids = alc861_adc_nids,
16068 .input_mux = &alc861_capture_source,
16069 },
Takashi Iwai22309c32006-08-09 16:57:28 +020016070 [ALC861_UNIWILL_M31] = {
16071 .mixers = { alc861_uniwill_m31_mixer },
16072 .init_verbs = { alc861_uniwill_m31_init_verbs },
16073 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16074 .dac_nids = alc861_dac_nids,
16075 .dig_out_nid = ALC861_DIGOUT_NID,
16076 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
16077 .channel_mode = alc861_uniwill_m31_modes,
16078 .need_dac_fix = 1,
16079 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16080 .adc_nids = alc861_adc_nids,
16081 .input_mux = &alc861_capture_source,
16082 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020016083 [ALC861_TOSHIBA] = {
16084 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016085 .init_verbs = { alc861_base_init_verbs,
16086 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020016087 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16088 .dac_nids = alc861_dac_nids,
16089 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
16090 .channel_mode = alc883_3ST_2ch_modes,
16091 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16092 .adc_nids = alc861_adc_nids,
16093 .input_mux = &alc861_capture_source,
16094 .unsol_event = alc861_toshiba_unsol_event,
16095 .init_hook = alc861_toshiba_automute,
16096 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020016097 [ALC861_ASUS] = {
16098 .mixers = { alc861_asus_mixer },
16099 .init_verbs = { alc861_asus_init_verbs },
16100 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16101 .dac_nids = alc861_dac_nids,
16102 .dig_out_nid = ALC861_DIGOUT_NID,
16103 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
16104 .channel_mode = alc861_asus_modes,
16105 .need_dac_fix = 1,
16106 .hp_nid = 0x06,
16107 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16108 .adc_nids = alc861_adc_nids,
16109 .input_mux = &alc861_capture_source,
16110 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010016111 [ALC861_ASUS_LAPTOP] = {
16112 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
16113 .init_verbs = { alc861_asus_init_verbs,
16114 alc861_asus_laptop_init_verbs },
16115 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16116 .dac_nids = alc861_dac_nids,
16117 .dig_out_nid = ALC861_DIGOUT_NID,
16118 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
16119 .channel_mode = alc883_3ST_2ch_modes,
16120 .need_dac_fix = 1,
16121 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16122 .adc_nids = alc861_adc_nids,
16123 .input_mux = &alc861_capture_source,
16124 },
16125};
Kailang Yangdf694da2005-12-05 19:42:22 +010016126
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016127/* Pin config fixes */
16128enum {
16129 PINFIX_FSC_AMILO_PI1505,
16130};
16131
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016132static const struct alc_fixup alc861_fixups[] = {
16133 [PINFIX_FSC_AMILO_PI1505] = {
Takashi Iwai73413b12010-08-30 09:39:57 +020016134 .pins = (const struct alc_pincfg[]) {
16135 { 0x0b, 0x0221101f }, /* HP */
16136 { 0x0f, 0x90170310 }, /* speaker */
16137 { }
16138 }
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016139 },
16140};
16141
16142static struct snd_pci_quirk alc861_fixup_tbl[] = {
16143 SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
16144 {}
16145};
Kailang Yangdf694da2005-12-05 19:42:22 +010016146
16147static int patch_alc861(struct hda_codec *codec)
16148{
16149 struct alc_spec *spec;
16150 int board_config;
16151 int err;
16152
Robert P. J. Daydc041e02006-12-19 14:44:15 +010016153 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010016154 if (spec == NULL)
16155 return -ENOMEM;
16156
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016157 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010016158
Takashi Iwaif5fcc132006-11-24 17:07:44 +010016159 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
16160 alc861_models,
16161 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016162
Takashi Iwaif5fcc132006-11-24 17:07:44 +010016163 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020016164 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
16165 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010016166 board_config = ALC861_AUTO;
16167 }
16168
Takashi Iwai7fa90e82010-04-12 08:49:00 +020016169 if (board_config == ALC861_AUTO)
16170 alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups, 1);
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016171
Kailang Yangdf694da2005-12-05 19:42:22 +010016172 if (board_config == ALC861_AUTO) {
16173 /* automatic parse from the BIOS config */
16174 err = alc861_parse_auto_config(codec);
16175 if (err < 0) {
16176 alc_free(codec);
16177 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016178 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016179 printk(KERN_INFO
16180 "hda_codec: Cannot set up configuration "
16181 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010016182 board_config = ALC861_3ST_DIG;
16183 }
16184 }
16185
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090016186 err = snd_hda_attach_beep_device(codec, 0x23);
16187 if (err < 0) {
16188 alc_free(codec);
16189 return err;
16190 }
16191
Kailang Yangdf694da2005-12-05 19:42:22 +010016192 if (board_config != ALC861_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020016193 setup_preset(codec, &alc861_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010016194
Kailang Yangdf694da2005-12-05 19:42:22 +010016195 spec->stream_analog_playback = &alc861_pcm_analog_playback;
16196 spec->stream_analog_capture = &alc861_pcm_analog_capture;
16197
Kailang Yangdf694da2005-12-05 19:42:22 +010016198 spec->stream_digital_playback = &alc861_pcm_digital_playback;
16199 spec->stream_digital_capture = &alc861_pcm_digital_capture;
16200
Takashi Iwaic7a8eb12010-01-14 12:39:02 +010016201 if (!spec->cap_mixer)
16202 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010016203 set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
16204
Takashi Iwai2134ea42008-01-10 16:53:55 +010016205 spec->vmaster_nid = 0x03;
16206
Takashi Iwai7fa90e82010-04-12 08:49:00 +020016207 if (board_config == ALC861_AUTO)
16208 alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups, 0);
16209
Kailang Yangdf694da2005-12-05 19:42:22 +010016210 codec->patch_ops = alc_patch_ops;
Daniel T Chenc97259d2009-12-27 18:52:08 -050016211 if (board_config == ALC861_AUTO) {
Takashi Iwaiae6b8132006-03-03 16:47:17 +010016212 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020016213#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050016214 spec->power_hook = alc_power_eapd;
16215#endif
16216 }
16217#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaicb53c622007-08-10 17:21:45 +020016218 if (!spec->loopback.amplist)
16219 spec->loopback.amplist = alc861_loopbacks;
16220#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020016221
Kailang Yangdf694da2005-12-05 19:42:22 +010016222 return 0;
16223}
16224
16225/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016226 * ALC861-VD support
16227 *
16228 * Based on ALC882
16229 *
16230 * In addition, an independent DAC
16231 */
16232#define ALC861VD_DIGOUT_NID 0x06
16233
16234static hda_nid_t alc861vd_dac_nids[4] = {
16235 /* front, surr, clfe, side surr */
16236 0x02, 0x03, 0x04, 0x05
16237};
16238
16239/* dac_nids for ALC660vd are in a different order - according to
16240 * Realtek's driver.
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016241 * This should probably result in a different mixer for 6stack models
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016242 * of ALC660vd codecs, but for now there is only 3stack mixer
16243 * - and it is the same as in 861vd.
16244 * adc_nids in ALC660vd are (is) the same as in 861vd
16245 */
16246static hda_nid_t alc660vd_dac_nids[3] = {
16247 /* front, rear, clfe, rear_surr */
16248 0x02, 0x04, 0x03
16249};
16250
16251static hda_nid_t alc861vd_adc_nids[1] = {
16252 /* ADC0 */
16253 0x09,
16254};
16255
Takashi Iwaie1406342008-02-11 18:32:32 +010016256static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
16257
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016258/* input MUX */
16259/* FIXME: should be a matrix-type input source selection */
16260static struct hda_input_mux alc861vd_capture_source = {
16261 .num_items = 4,
16262 .items = {
16263 { "Mic", 0x0 },
16264 { "Front Mic", 0x1 },
16265 { "Line", 0x2 },
16266 { "CD", 0x4 },
16267 },
16268};
16269
Kailang Yang272a5272007-05-14 11:00:38 +020016270static struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010016271 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020016272 .items = {
Tobin Davisb419f342008-03-07 11:57:51 +010016273 { "Ext Mic", 0x0 },
16274 { "Int Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020016275 },
16276};
16277
Kailang Yangd1a991a2007-08-15 16:21:59 +020016278static struct hda_input_mux alc861vd_hp_capture_source = {
16279 .num_items = 2,
16280 .items = {
16281 { "Front Mic", 0x0 },
16282 { "ATAPI Mic", 0x1 },
16283 },
16284};
16285
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016286/*
16287 * 2ch mode
16288 */
16289static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
16290 { 2, NULL }
16291};
16292
16293/*
16294 * 6ch mode
16295 */
16296static struct hda_verb alc861vd_6stack_ch6_init[] = {
16297 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
16298 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16299 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16300 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16301 { } /* end */
16302};
16303
16304/*
16305 * 8ch mode
16306 */
16307static struct hda_verb alc861vd_6stack_ch8_init[] = {
16308 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16309 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16310 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16311 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16312 { } /* end */
16313};
16314
16315static struct hda_channel_mode alc861vd_6stack_modes[2] = {
16316 { 6, alc861vd_6stack_ch6_init },
16317 { 8, alc861vd_6stack_ch8_init },
16318};
16319
16320static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
16321 {
16322 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
16323 .name = "Channel Mode",
16324 .info = alc_ch_mode_info,
16325 .get = alc_ch_mode_get,
16326 .put = alc_ch_mode_put,
16327 },
16328 { } /* end */
16329};
16330
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016331/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
16332 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
16333 */
16334static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
16335 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16336 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16337
16338 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16339 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
16340
16341 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
16342 HDA_OUTPUT),
16343 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
16344 HDA_OUTPUT),
16345 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
16346 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
16347
16348 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
16349 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
16350
16351 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16352
16353 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
16354 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16355 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16356
16357 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
16358 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16359 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16360
16361 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16362 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16363
16364 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16365 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16366
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016367 { } /* end */
16368};
16369
16370static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
16371 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16372 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16373
16374 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16375
16376 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
16377 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16378 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16379
16380 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
16381 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16382 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16383
16384 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16385 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16386
16387 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16388 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16389
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016390 { } /* end */
16391};
16392
Kailang Yangbdd148a2007-05-08 15:19:08 +020016393static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
16394 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16395 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
16396 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
16397
16398 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16399
16400 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
16401 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16402 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16403
16404 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
16405 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16406 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16407
16408 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16409 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16410
16411 { } /* end */
16412};
16413
Tobin Davisb419f342008-03-07 11:57:51 +010016414/* Pin assignment: Speaker=0x14, HP = 0x15,
16415 * Ext Mic=0x18, Int Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020016416 */
16417static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010016418 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16419 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020016420 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16421 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisb419f342008-03-07 11:57:51 +010016422 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
16423 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16424 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16425 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
16426 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16427 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020016428 { } /* end */
16429};
16430
Kailang Yangd1a991a2007-08-15 16:21:59 +020016431/* Pin assignment: Speaker=0x14, Line-out = 0x15,
16432 * Front Mic=0x18, ATAPI Mic = 0x19,
16433 */
16434static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
16435 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16436 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16437 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16438 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
16439 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16440 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16441 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16442 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020016443
Kailang Yangd1a991a2007-08-15 16:21:59 +020016444 { } /* end */
16445};
16446
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016447/*
16448 * generic initialization of ADC, input mixers and output mixers
16449 */
16450static struct hda_verb alc861vd_volume_init_verbs[] = {
16451 /*
16452 * Unmute ADC0 and set the default input to mic-in
16453 */
16454 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
16455 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16456
16457 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
16458 * the analog-loopback mixer widget
16459 */
16460 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020016461 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16462 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16463 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16464 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16465 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016466
16467 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020016468 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16469 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16470 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016471 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016472
16473 /*
16474 * Set up output mixers (0x02 - 0x05)
16475 */
16476 /* set vol=0 to output mixers */
16477 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16478 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16479 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16480 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16481
16482 /* set up input amps for analog loopback */
16483 /* Amp Indices: DAC = 0, mixer = 1 */
16484 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16485 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16486 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16487 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16488 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16489 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16490 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16491 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16492
16493 { }
16494};
16495
16496/*
16497 * 3-stack pin configuration:
16498 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
16499 */
16500static struct hda_verb alc861vd_3stack_init_verbs[] = {
16501 /*
16502 * Set pin mode and muting
16503 */
16504 /* set front pin widgets 0x14 for output */
16505 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16506 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16507 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16508
16509 /* Mic (rear) pin: input vref at 80% */
16510 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16511 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16512 /* Front Mic pin: input vref at 80% */
16513 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16514 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16515 /* Line In pin: input */
16516 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16517 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16518 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16519 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16520 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16521 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16522 /* CD pin widget for input */
16523 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16524
16525 { }
16526};
16527
16528/*
16529 * 6-stack pin configuration:
16530 */
16531static struct hda_verb alc861vd_6stack_init_verbs[] = {
16532 /*
16533 * Set pin mode and muting
16534 */
16535 /* set front pin widgets 0x14 for output */
16536 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16537 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16538 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16539
16540 /* Rear Pin: output 1 (0x0d) */
16541 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16542 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16543 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
16544 /* CLFE Pin: output 2 (0x0e) */
16545 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16546 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16547 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
16548 /* Side Pin: output 3 (0x0f) */
16549 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16550 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16551 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
16552
16553 /* Mic (rear) pin: input vref at 80% */
16554 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16555 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16556 /* Front Mic pin: input vref at 80% */
16557 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16558 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16559 /* Line In pin: input */
16560 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16561 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16562 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16563 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16564 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16565 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16566 /* CD pin widget for input */
16567 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16568
16569 { }
16570};
16571
Kailang Yangbdd148a2007-05-08 15:19:08 +020016572static struct hda_verb alc861vd_eapd_verbs[] = {
16573 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16574 { }
16575};
16576
Kailang Yangf9423e72008-05-27 12:32:25 +020016577static struct hda_verb alc660vd_eapd_verbs[] = {
16578 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16579 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
16580 { }
16581};
16582
Kailang Yangbdd148a2007-05-08 15:19:08 +020016583static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
16584 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16585 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16586 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
16587 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020016588 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020016589 {}
16590};
16591
Kailang Yangbdd148a2007-05-08 15:19:08 +020016592static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
16593{
16594 unsigned int present;
16595 unsigned char bits;
16596
Wu Fengguang864f92b2009-11-18 12:38:02 +080016597 present = snd_hda_jack_detect(codec, 0x18);
Takashi Iwai47fd8302007-08-10 17:11:07 +020016598 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080016599
Takashi Iwai47fd8302007-08-10 17:11:07 +020016600 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
16601 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016602}
16603
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016604static void alc861vd_lenovo_setup(struct hda_codec *codec)
Kailang Yangbdd148a2007-05-08 15:19:08 +020016605{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016606 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016607 spec->autocfg.hp_pins[0] = 0x1b;
16608 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016609}
16610
16611static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
16612{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016613 alc_automute_amp(codec);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016614 alc861vd_lenovo_mic_automute(codec);
16615}
16616
16617static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
16618 unsigned int res)
16619{
16620 switch (res >> 26) {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016621 case ALC880_MIC_EVENT:
16622 alc861vd_lenovo_mic_automute(codec);
16623 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016624 default:
16625 alc_automute_amp_unsol_event(codec, res);
16626 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +020016627 }
16628}
16629
Kailang Yang272a5272007-05-14 11:00:38 +020016630static struct hda_verb alc861vd_dallas_verbs[] = {
16631 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16632 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16633 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16634 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16635
16636 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16637 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16638 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16639 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16640 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16641 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16642 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16643 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016644
Kailang Yang272a5272007-05-14 11:00:38 +020016645 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16646 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16647 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16648 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16649 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16650 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16651 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16652 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16653
16654 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16655 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16656 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16657 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16658 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16659 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16660 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16661 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16662
16663 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16664 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16665 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16666 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
16667
16668 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016669 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020016670 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16671
16672 { } /* end */
16673};
16674
16675/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016676static void alc861vd_dallas_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +020016677{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016678 struct alc_spec *spec = codec->spec;
Kailang Yang272a5272007-05-14 11:00:38 +020016679
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016680 spec->autocfg.hp_pins[0] = 0x15;
16681 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang272a5272007-05-14 11:00:38 +020016682}
16683
Takashi Iwaicb53c622007-08-10 17:21:45 +020016684#ifdef CONFIG_SND_HDA_POWER_SAVE
16685#define alc861vd_loopbacks alc880_loopbacks
16686#endif
16687
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016688/* pcm configuration: identical with ALC880 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016689#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
16690#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
16691#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
16692#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
16693
16694/*
16695 * configuration and preset
16696 */
16697static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
16698 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016699 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Takashi Iwai13c94742008-11-05 08:06:08 +010016700 [ALC660VD_ASUS_V1S] = "asus-v1s",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016701 [ALC861VD_3ST] = "3stack",
16702 [ALC861VD_3ST_DIG] = "3stack-digout",
16703 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020016704 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020016705 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016706 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016707 [ALC861VD_AUTO] = "auto",
16708};
16709
16710static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016711 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
16712 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010016713 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016714 /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */
Takashi Iwai13c94742008-11-05 08:06:08 +010016715 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
Mike Crash6963f842007-06-25 12:12:51 +020016716 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016717 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016718 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020016719 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Takashi Iwaice577e82009-08-03 08:23:52 +020016720 SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai542d7c62007-08-16 18:57:30 +020016721 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010016722 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020016723 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016724 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020016725 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016726 {}
16727};
16728
16729static struct alc_config_preset alc861vd_presets[] = {
16730 [ALC660VD_3ST] = {
16731 .mixers = { alc861vd_3st_mixer },
16732 .init_verbs = { alc861vd_volume_init_verbs,
16733 alc861vd_3stack_init_verbs },
16734 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16735 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016736 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16737 .channel_mode = alc861vd_3stack_2ch_modes,
16738 .input_mux = &alc861vd_capture_source,
16739 },
Mike Crash6963f842007-06-25 12:12:51 +020016740 [ALC660VD_3ST_DIG] = {
16741 .mixers = { alc861vd_3st_mixer },
16742 .init_verbs = { alc861vd_volume_init_verbs,
16743 alc861vd_3stack_init_verbs },
16744 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16745 .dac_nids = alc660vd_dac_nids,
16746 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020016747 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16748 .channel_mode = alc861vd_3stack_2ch_modes,
16749 .input_mux = &alc861vd_capture_source,
16750 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016751 [ALC861VD_3ST] = {
16752 .mixers = { alc861vd_3st_mixer },
16753 .init_verbs = { alc861vd_volume_init_verbs,
16754 alc861vd_3stack_init_verbs },
16755 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16756 .dac_nids = alc861vd_dac_nids,
16757 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16758 .channel_mode = alc861vd_3stack_2ch_modes,
16759 .input_mux = &alc861vd_capture_source,
16760 },
16761 [ALC861VD_3ST_DIG] = {
16762 .mixers = { alc861vd_3st_mixer },
16763 .init_verbs = { alc861vd_volume_init_verbs,
16764 alc861vd_3stack_init_verbs },
16765 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16766 .dac_nids = alc861vd_dac_nids,
16767 .dig_out_nid = ALC861VD_DIGOUT_NID,
16768 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16769 .channel_mode = alc861vd_3stack_2ch_modes,
16770 .input_mux = &alc861vd_capture_source,
16771 },
16772 [ALC861VD_6ST_DIG] = {
16773 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
16774 .init_verbs = { alc861vd_volume_init_verbs,
16775 alc861vd_6stack_init_verbs },
16776 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16777 .dac_nids = alc861vd_dac_nids,
16778 .dig_out_nid = ALC861VD_DIGOUT_NID,
16779 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
16780 .channel_mode = alc861vd_6stack_modes,
16781 .input_mux = &alc861vd_capture_source,
16782 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020016783 [ALC861VD_LENOVO] = {
16784 .mixers = { alc861vd_lenovo_mixer },
16785 .init_verbs = { alc861vd_volume_init_verbs,
16786 alc861vd_3stack_init_verbs,
16787 alc861vd_eapd_verbs,
16788 alc861vd_lenovo_unsol_verbs },
16789 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16790 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016791 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16792 .channel_mode = alc861vd_3stack_2ch_modes,
16793 .input_mux = &alc861vd_capture_source,
16794 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016795 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016796 .init_hook = alc861vd_lenovo_init_hook,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016797 },
Kailang Yang272a5272007-05-14 11:00:38 +020016798 [ALC861VD_DALLAS] = {
16799 .mixers = { alc861vd_dallas_mixer },
16800 .init_verbs = { alc861vd_dallas_verbs },
16801 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16802 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020016803 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16804 .channel_mode = alc861vd_3stack_2ch_modes,
16805 .input_mux = &alc861vd_dallas_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016806 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016807 .setup = alc861vd_dallas_setup,
16808 .init_hook = alc_automute_amp,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016809 },
16810 [ALC861VD_HP] = {
16811 .mixers = { alc861vd_hp_mixer },
16812 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
16813 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16814 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016815 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016816 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16817 .channel_mode = alc861vd_3stack_2ch_modes,
16818 .input_mux = &alc861vd_hp_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016819 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016820 .setup = alc861vd_dallas_setup,
16821 .init_hook = alc_automute_amp,
Kailang Yangea1fb292008-08-26 12:58:38 +020016822 },
Takashi Iwai13c94742008-11-05 08:06:08 +010016823 [ALC660VD_ASUS_V1S] = {
16824 .mixers = { alc861vd_lenovo_mixer },
16825 .init_verbs = { alc861vd_volume_init_verbs,
16826 alc861vd_3stack_init_verbs,
16827 alc861vd_eapd_verbs,
16828 alc861vd_lenovo_unsol_verbs },
16829 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16830 .dac_nids = alc660vd_dac_nids,
16831 .dig_out_nid = ALC861VD_DIGOUT_NID,
16832 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16833 .channel_mode = alc861vd_3stack_2ch_modes,
16834 .input_mux = &alc861vd_capture_source,
16835 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016836 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016837 .init_hook = alc861vd_lenovo_init_hook,
Takashi Iwai13c94742008-11-05 08:06:08 +010016838 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016839};
16840
16841/*
16842 * BIOS auto configuration
16843 */
Takashi Iwai05f5f472009-08-25 13:10:18 +020016844static int alc861vd_auto_create_input_ctls(struct hda_codec *codec,
16845 const struct auto_pin_cfg *cfg)
16846{
Kailang Yang6227cdc2010-02-25 08:36:52 +010016847 return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x09, 0);
Takashi Iwai05f5f472009-08-25 13:10:18 +020016848}
16849
16850
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016851static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
16852 hda_nid_t nid, int pin_type, int dac_idx)
16853{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016854 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016855}
16856
16857static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
16858{
16859 struct alc_spec *spec = codec->spec;
16860 int i;
16861
16862 for (i = 0; i <= HDA_SIDE; i++) {
16863 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016864 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016865 if (nid)
16866 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016867 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016868 }
16869}
16870
16871
16872static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
16873{
16874 struct alc_spec *spec = codec->spec;
16875 hda_nid_t pin;
16876
16877 pin = spec->autocfg.hp_pins[0];
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016878 if (pin) /* connect to front and use dac 0 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016879 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016880 pin = spec->autocfg.speaker_pins[0];
16881 if (pin)
16882 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016883}
16884
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016885#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
16886
16887static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
16888{
16889 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020016890 struct auto_pin_cfg *cfg = &spec->autocfg;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016891 int i;
16892
Takashi Iwai66ceeb62010-08-30 13:05:52 +020016893 for (i = 0; i < cfg->num_inputs; i++) {
16894 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +020016895 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai30ea0982010-09-16 18:47:56 +020016896 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwaie82c0252009-03-23 15:17:38 +010016897 if (nid != ALC861VD_PIN_CD_NID &&
16898 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016899 snd_hda_codec_write(codec, nid, 0,
16900 AC_VERB_SET_AMP_GAIN_MUTE,
16901 AMP_OUT_MUTE);
16902 }
16903 }
16904}
16905
Takashi Iwaif511b012008-08-15 16:46:42 +020016906#define alc861vd_auto_init_input_src alc882_auto_init_input_src
16907
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016908#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
16909#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
16910
16911/* add playback controls from the parsed DAC table */
16912/* Based on ALC880 version. But ALC861VD has separate,
16913 * different NIDs for mute/unmute switch and volume control */
16914static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
16915 const struct auto_pin_cfg *cfg)
16916{
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016917 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
16918 hda_nid_t nid_v, nid_s;
16919 int i, err;
16920
16921 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016922 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016923 continue;
16924 nid_v = alc861vd_idx_to_mixer_vol(
16925 alc880_dac_to_idx(
16926 spec->multiout.dac_nids[i]));
16927 nid_s = alc861vd_idx_to_mixer_switch(
16928 alc880_dac_to_idx(
16929 spec->multiout.dac_nids[i]));
16930
16931 if (i == 2) {
16932 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016933 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
16934 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016935 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
16936 HDA_OUTPUT));
16937 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016938 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016939 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
16940 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016941 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
16942 HDA_OUTPUT));
16943 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016944 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016945 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
16946 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016947 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
16948 HDA_INPUT));
16949 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016950 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016951 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
16952 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016953 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
16954 HDA_INPUT));
16955 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016956 return err;
16957 } else {
Takashi Iwaia4fcd492009-08-25 16:12:15 +020016958 const char *pfx;
16959 if (cfg->line_outs == 1 &&
16960 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
16961 if (!cfg->hp_pins)
16962 pfx = "Speaker";
16963 else
16964 pfx = "PCM";
16965 } else
16966 pfx = chname[i];
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016967 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016968 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
16969 HDA_OUTPUT));
16970 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016971 return err;
Takashi Iwaia4fcd492009-08-25 16:12:15 +020016972 if (cfg->line_outs == 1 &&
16973 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
16974 pfx = "Speaker";
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016975 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016976 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016977 HDA_INPUT));
16978 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016979 return err;
16980 }
16981 }
16982 return 0;
16983}
16984
16985/* add playback controls for speaker and HP outputs */
16986/* Based on ALC880 version. But ALC861VD has separate,
16987 * different NIDs for mute/unmute switch and volume control */
16988static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
16989 hda_nid_t pin, const char *pfx)
16990{
16991 hda_nid_t nid_v, nid_s;
16992 int err;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016993
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016994 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016995 return 0;
16996
16997 if (alc880_is_fixed_pin(pin)) {
16998 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
16999 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017000 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017001 spec->multiout.hp_nid = nid_v;
17002 else
17003 spec->multiout.extra_out_nid[0] = nid_v;
17004 /* control HP volume/switch on the output mixer amp */
17005 nid_v = alc861vd_idx_to_mixer_vol(
17006 alc880_fixed_pin_idx(pin));
17007 nid_s = alc861vd_idx_to_mixer_switch(
17008 alc880_fixed_pin_idx(pin));
17009
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017010 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017011 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
17012 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017013 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017014 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017015 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
17016 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017017 return err;
17018 } else if (alc880_is_multi_pin(pin)) {
17019 /* set manual connection */
17020 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017021 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017022 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
17023 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017024 return err;
17025 }
17026 return 0;
17027}
17028
17029/* parse the BIOS configuration and set up the alc_spec
17030 * return 1 if successful, 0 if the proper config is not found,
17031 * or a negative error code
17032 * Based on ALC880 version - had to change it to override
17033 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
17034static int alc861vd_parse_auto_config(struct hda_codec *codec)
17035{
17036 struct alc_spec *spec = codec->spec;
17037 int err;
17038 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
17039
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017040 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
17041 alc861vd_ignore);
17042 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017043 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017044 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017045 return 0; /* can't find valid BIOS pin config */
17046
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017047 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
17048 if (err < 0)
17049 return err;
17050 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
17051 if (err < 0)
17052 return err;
17053 err = alc861vd_auto_create_extra_out(spec,
17054 spec->autocfg.speaker_pins[0],
17055 "Speaker");
17056 if (err < 0)
17057 return err;
17058 err = alc861vd_auto_create_extra_out(spec,
17059 spec->autocfg.hp_pins[0],
17060 "Headphone");
17061 if (err < 0)
17062 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020017063 err = alc861vd_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017064 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017065 return err;
17066
17067 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
17068
Takashi Iwai757899a2010-07-30 10:48:14 +020017069 alc_auto_parse_digital(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017070
Takashi Iwai603c4012008-07-30 15:01:44 +020017071 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010017072 add_mixer(spec, spec->kctls.list);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017073
Takashi Iwaid88897e2008-10-31 15:01:37 +010017074 add_verb(spec, alc861vd_volume_init_verbs);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017075
17076 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020017077 spec->input_mux = &spec->private_imux[0];
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017078
Takashi Iwai776e1842007-08-29 15:07:11 +020017079 err = alc_auto_add_mic_boost(codec);
17080 if (err < 0)
17081 return err;
17082
Kailang Yang6227cdc2010-02-25 08:36:52 +010017083 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020017084
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017085 return 1;
17086}
17087
17088/* additional initialization for auto-configuration model */
17089static void alc861vd_auto_init(struct hda_codec *codec)
17090{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017091 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017092 alc861vd_auto_init_multi_out(codec);
17093 alc861vd_auto_init_hp_out(codec);
17094 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020017095 alc861vd_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020017096 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017097 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020017098 alc_inithook(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017099}
17100
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017101enum {
17102 ALC660VD_FIX_ASUS_GPIO1
17103};
17104
17105/* reset GPIO1 */
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017106static const struct alc_fixup alc861vd_fixups[] = {
17107 [ALC660VD_FIX_ASUS_GPIO1] = {
Takashi Iwai73413b12010-08-30 09:39:57 +020017108 .verbs = (const struct hda_verb[]) {
17109 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
17110 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
17111 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
17112 { }
17113 }
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017114 },
17115};
17116
17117static struct snd_pci_quirk alc861vd_fixup_tbl[] = {
17118 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
17119 {}
17120};
17121
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017122static int patch_alc861vd(struct hda_codec *codec)
17123{
17124 struct alc_spec *spec;
17125 int err, board_config;
17126
17127 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
17128 if (spec == NULL)
17129 return -ENOMEM;
17130
17131 codec->spec = spec;
17132
17133 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
17134 alc861vd_models,
17135 alc861vd_cfg_tbl);
17136
17137 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020017138 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
17139 codec->chip_name);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017140 board_config = ALC861VD_AUTO;
17141 }
17142
Takashi Iwai7fa90e82010-04-12 08:49:00 +020017143 if (board_config == ALC861VD_AUTO)
17144 alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups, 1);
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017145
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017146 if (board_config == ALC861VD_AUTO) {
17147 /* automatic parse from the BIOS config */
17148 err = alc861vd_parse_auto_config(codec);
17149 if (err < 0) {
17150 alc_free(codec);
17151 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017152 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017153 printk(KERN_INFO
17154 "hda_codec: Cannot set up configuration "
17155 "from BIOS. Using base mode...\n");
17156 board_config = ALC861VD_3ST;
17157 }
17158 }
17159
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090017160 err = snd_hda_attach_beep_device(codec, 0x23);
17161 if (err < 0) {
17162 alc_free(codec);
17163 return err;
17164 }
17165
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017166 if (board_config != ALC861VD_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020017167 setup_preset(codec, &alc861vd_presets[board_config]);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017168
Kailang Yang2f893282008-05-27 12:14:47 +020017169 if (codec->vendor_id == 0x10ec0660) {
Kailang Yangf9423e72008-05-27 12:32:25 +020017170 /* always turn on EAPD */
Takashi Iwaid88897e2008-10-31 15:01:37 +010017171 add_verb(spec, alc660vd_eapd_verbs);
Kailang Yang2f893282008-05-27 12:14:47 +020017172 }
17173
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017174 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
17175 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
17176
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017177 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
17178 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
17179
Takashi Iwaidd704692009-08-11 08:45:11 +020017180 if (!spec->adc_nids) {
17181 spec->adc_nids = alc861vd_adc_nids;
17182 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
17183 }
17184 if (!spec->capsrc_nids)
17185 spec->capsrc_nids = alc861vd_capsrc_nids;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017186
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017187 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010017188 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017189
Takashi Iwai2134ea42008-01-10 16:53:55 +010017190 spec->vmaster_nid = 0x02;
17191
Takashi Iwai7fa90e82010-04-12 08:49:00 +020017192 if (board_config == ALC861VD_AUTO)
17193 alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups, 0);
17194
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017195 codec->patch_ops = alc_patch_ops;
17196
17197 if (board_config == ALC861VD_AUTO)
17198 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020017199#ifdef CONFIG_SND_HDA_POWER_SAVE
17200 if (!spec->loopback.amplist)
17201 spec->loopback.amplist = alc861vd_loopbacks;
17202#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017203
17204 return 0;
17205}
17206
17207/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017208 * ALC662 support
17209 *
17210 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
17211 * configuration. Each pin widget can choose any input DACs and a mixer.
17212 * Each ADC is connected from a mixer of all inputs. This makes possible
17213 * 6-channel independent captures.
17214 *
17215 * In addition, an independent DAC for the multi-playback (not used in this
17216 * driver yet).
17217 */
17218#define ALC662_DIGOUT_NID 0x06
17219#define ALC662_DIGIN_NID 0x0a
17220
17221static hda_nid_t alc662_dac_nids[4] = {
17222 /* front, rear, clfe, rear_surr */
17223 0x02, 0x03, 0x04
17224};
17225
Kailang Yang622e84c2009-04-21 07:39:04 +020017226static hda_nid_t alc272_dac_nids[2] = {
17227 0x02, 0x03
17228};
17229
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017230static hda_nid_t alc662_adc_nids[2] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017231 /* ADC1-2 */
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017232 0x09, 0x08
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017233};
Takashi Iwaie1406342008-02-11 18:32:32 +010017234
Kailang Yang622e84c2009-04-21 07:39:04 +020017235static hda_nid_t alc272_adc_nids[1] = {
17236 /* ADC1-2 */
17237 0x08,
17238};
17239
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017240static hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 };
Kailang Yang622e84c2009-04-21 07:39:04 +020017241static hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
17242
Takashi Iwaie1406342008-02-11 18:32:32 +010017243
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017244/* input MUX */
17245/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017246static struct hda_input_mux alc662_capture_source = {
17247 .num_items = 4,
17248 .items = {
17249 { "Mic", 0x0 },
17250 { "Front Mic", 0x1 },
17251 { "Line", 0x2 },
17252 { "CD", 0x4 },
17253 },
17254};
17255
17256static struct hda_input_mux alc662_lenovo_101e_capture_source = {
17257 .num_items = 2,
17258 .items = {
17259 { "Mic", 0x1 },
17260 { "Line", 0x2 },
17261 },
17262};
Kailang Yang291702f2007-10-16 14:28:03 +020017263
Kailang Yang6dda9f42008-05-27 12:05:31 +020017264static struct hda_input_mux alc663_capture_source = {
17265 .num_items = 3,
17266 .items = {
17267 { "Mic", 0x0 },
17268 { "Front Mic", 0x1 },
17269 { "Line", 0x2 },
17270 },
17271};
17272
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017273#if 0 /* set to 1 for testing other input sources below */
Chris Pockelé9541ba12009-05-12 08:08:53 +020017274static struct hda_input_mux alc272_nc10_capture_source = {
17275 .num_items = 16,
17276 .items = {
17277 { "Autoselect Mic", 0x0 },
17278 { "Internal Mic", 0x1 },
17279 { "In-0x02", 0x2 },
17280 { "In-0x03", 0x3 },
17281 { "In-0x04", 0x4 },
17282 { "In-0x05", 0x5 },
17283 { "In-0x06", 0x6 },
17284 { "In-0x07", 0x7 },
17285 { "In-0x08", 0x8 },
17286 { "In-0x09", 0x9 },
17287 { "In-0x0a", 0x0a },
17288 { "In-0x0b", 0x0b },
17289 { "In-0x0c", 0x0c },
17290 { "In-0x0d", 0x0d },
17291 { "In-0x0e", 0x0e },
17292 { "In-0x0f", 0x0f },
17293 },
17294};
17295#endif
17296
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017297/*
17298 * 2ch mode
17299 */
17300static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
17301 { 2, NULL }
17302};
17303
17304/*
17305 * 2ch mode
17306 */
17307static struct hda_verb alc662_3ST_ch2_init[] = {
17308 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
17309 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
17310 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
17311 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
17312 { } /* end */
17313};
17314
17315/*
17316 * 6ch mode
17317 */
17318static struct hda_verb alc662_3ST_ch6_init[] = {
17319 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17320 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
17321 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
17322 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17323 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
17324 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
17325 { } /* end */
17326};
17327
17328static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
17329 { 2, alc662_3ST_ch2_init },
17330 { 6, alc662_3ST_ch6_init },
17331};
17332
17333/*
17334 * 2ch mode
17335 */
17336static struct hda_verb alc662_sixstack_ch6_init[] = {
17337 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
17338 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
17339 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17340 { } /* end */
17341};
17342
17343/*
17344 * 6ch mode
17345 */
17346static struct hda_verb alc662_sixstack_ch8_init[] = {
17347 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17348 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17349 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17350 { } /* end */
17351};
17352
17353static struct hda_channel_mode alc662_5stack_modes[2] = {
17354 { 2, alc662_sixstack_ch6_init },
17355 { 6, alc662_sixstack_ch8_init },
17356};
17357
17358/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
17359 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
17360 */
17361
17362static struct snd_kcontrol_new alc662_base_mixer[] = {
17363 /* output mixer control */
17364 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017365 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017366 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017367 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017368 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17369 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017370 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
17371 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017372 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17373
17374 /*Input mixer control */
17375 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
17376 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
17377 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
17378 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
17379 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
17380 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
17381 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
17382 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017383 { } /* end */
17384};
17385
17386static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
17387 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017388 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017389 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17390 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
17391 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
17392 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17393 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17394 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17395 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17396 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17397 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017398 { } /* end */
17399};
17400
17401static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
17402 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017403 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017404 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017405 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017406 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17407 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017408 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
17409 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017410 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17411 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
17412 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
17413 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17414 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17415 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17416 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17417 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17418 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017419 { } /* end */
17420};
17421
17422static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
17423 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17424 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010017425 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17426 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017427 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17428 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17429 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17430 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17431 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017432 { } /* end */
17433};
17434
Kailang Yang291702f2007-10-16 14:28:03 +020017435static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020017436 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17437 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang291702f2007-10-16 14:28:03 +020017438
17439 HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
17440 HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17441 HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17442
17443 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
17444 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17445 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17446 { } /* end */
17447};
17448
Kailang Yang8c427222008-01-10 13:03:59 +010017449static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020017450 ALC262_HIPPO_MASTER_SWITCH,
17451 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017452 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017453 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17454 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017455 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
17456 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17457 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17458 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17459 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17460 { } /* end */
17461};
17462
Kailang Yangf1d4e282008-08-26 14:03:29 +020017463static struct hda_bind_ctls alc663_asus_bind_master_vol = {
17464 .ops = &snd_hda_bind_vol,
17465 .values = {
17466 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17467 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
17468 0
17469 },
17470};
17471
17472static struct hda_bind_ctls alc663_asus_one_bind_switch = {
17473 .ops = &snd_hda_bind_sw,
17474 .values = {
17475 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17476 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17477 0
17478 },
17479};
17480
Kailang Yang6dda9f42008-05-27 12:05:31 +020017481static struct snd_kcontrol_new alc663_m51va_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017482 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17483 HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
17484 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17485 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17486 { } /* end */
17487};
17488
17489static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
17490 .ops = &snd_hda_bind_sw,
17491 .values = {
17492 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17493 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17494 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17495 0
17496 },
17497};
17498
17499static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
17500 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17501 HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
17502 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17503 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17504 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17505 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17506
17507 { } /* end */
17508};
17509
17510static struct hda_bind_ctls alc663_asus_four_bind_switch = {
17511 .ops = &snd_hda_bind_sw,
17512 .values = {
17513 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17514 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17515 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17516 0
17517 },
17518};
17519
17520static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
17521 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17522 HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
17523 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17524 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17525 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17526 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17527 { } /* end */
17528};
17529
17530static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017531 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17532 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017533 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17534 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17535 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17536 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17537 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17538 { } /* end */
17539};
17540
17541static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
17542 .ops = &snd_hda_bind_vol,
17543 .values = {
17544 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17545 HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
17546 0
17547 },
17548};
17549
17550static struct hda_bind_ctls alc663_asus_two_bind_switch = {
17551 .ops = &snd_hda_bind_sw,
17552 .values = {
17553 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17554 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
17555 0
17556 },
17557};
17558
17559static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
17560 HDA_BIND_VOL("Master Playback Volume",
17561 &alc663_asus_two_bind_master_vol),
17562 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17563 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017564 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17565 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17566 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017567 { } /* end */
17568};
17569
17570static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
17571 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17572 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17573 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17574 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17575 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17576 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017577 { } /* end */
17578};
17579
17580static struct snd_kcontrol_new alc663_g71v_mixer[] = {
17581 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17582 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17583 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17584 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17585 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17586
17587 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17588 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17589 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17590 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17591 { } /* end */
17592};
17593
17594static struct snd_kcontrol_new alc663_g50v_mixer[] = {
17595 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17596 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17597 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17598
17599 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17600 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17601 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17602 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17603 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17604 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17605 { } /* end */
17606};
17607
Kailang Yangebb83ee2009-12-17 12:23:00 +010017608static struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = {
17609 .ops = &snd_hda_bind_sw,
17610 .values = {
17611 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17612 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17613 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17614 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17615 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17616 0
17617 },
17618};
17619
17620static struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = {
17621 .ops = &snd_hda_bind_sw,
17622 .values = {
17623 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17624 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17625 0
17626 },
17627};
17628
17629static struct snd_kcontrol_new alc663_mode7_mixer[] = {
17630 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17631 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17632 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17633 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17634 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17635 HDA_CODEC_VOLUME("IntMic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17636 HDA_CODEC_MUTE("IntMic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17637 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17638 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17639 { } /* end */
17640};
17641
17642static struct snd_kcontrol_new alc663_mode8_mixer[] = {
17643 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17644 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17645 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17646 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17647 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17648 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17649 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17650 { } /* end */
17651};
17652
17653
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017654static struct snd_kcontrol_new alc662_chmode_mixer[] = {
17655 {
17656 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
17657 .name = "Channel Mode",
17658 .info = alc_ch_mode_info,
17659 .get = alc_ch_mode_get,
17660 .put = alc_ch_mode_put,
17661 },
17662 { } /* end */
17663};
17664
17665static struct hda_verb alc662_init_verbs[] = {
17666 /* ADC: mute amp left and right */
17667 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17668 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017669
Kailang Yangb60dd392007-09-20 12:50:29 +020017670 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17671 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17672 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17673 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17674 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17675 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017676
17677 /* Front Pin: output 0 (0x0c) */
17678 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17679 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17680
17681 /* Rear Pin: output 1 (0x0d) */
17682 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17683 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17684
17685 /* CLFE Pin: output 2 (0x0e) */
17686 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17687 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17688
17689 /* Mic (rear) pin: input vref at 80% */
17690 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17691 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17692 /* Front Mic pin: input vref at 80% */
17693 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17694 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17695 /* Line In pin: input */
17696 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17697 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17698 /* Line-2 In: Headphone output (output 0 - 0x0c) */
17699 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17700 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17701 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
17702 /* CD pin widget for input */
17703 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17704
17705 /* FIXME: use matrix-type input source selection */
17706 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
17707 /* Input mixer */
17708 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang291702f2007-10-16 14:28:03 +020017709 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017710
17711 /* always trun on EAPD */
17712 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
17713 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
17714
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017715 { }
17716};
17717
Kailang Yangcec27c82010-02-04 14:18:18 +010017718static struct hda_verb alc663_init_verbs[] = {
17719 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17720 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17721 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17722 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17723 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17724 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17725 { }
17726};
17727
17728static struct hda_verb alc272_init_verbs[] = {
17729 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17730 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17731 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17732 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17733 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17734 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17735 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17736 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17737 { }
17738};
17739
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017740static struct hda_verb alc662_sue_init_verbs[] = {
17741 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
17742 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020017743 {}
17744};
17745
17746static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
17747 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17748 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17749 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017750};
17751
Kailang Yang8c427222008-01-10 13:03:59 +010017752/* Set Unsolicited Event*/
17753static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
17754 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17755 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17756 {}
17757};
17758
Kailang Yang6dda9f42008-05-27 12:05:31 +020017759static struct hda_verb alc663_m51va_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017760 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17761 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017762 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17763 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf1d4e282008-08-26 14:03:29 +020017764 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17765 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17766 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017767 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17768 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17769 {}
17770};
17771
Kailang Yangf1d4e282008-08-26 14:03:29 +020017772static struct hda_verb alc663_21jd_amic_init_verbs[] = {
17773 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17774 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17775 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17776 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17777 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17778 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17779 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17780 {}
17781};
17782
17783static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
17784 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17785 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17786 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17787 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17788 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17789 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17790 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17791 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17792 {}
17793};
17794
17795static struct hda_verb alc663_15jd_amic_init_verbs[] = {
17796 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17797 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17798 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17799 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17800 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17801 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17802 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17803 {}
17804};
17805
17806static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
17807 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17808 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17809 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17810 {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
17811 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17812 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17813 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
17814 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17815 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17816 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17817 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17818 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17819 {}
17820};
17821
17822static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
17823 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17824 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17825 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17826 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17827 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17828 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17829 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17830 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17831 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17832 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17833 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17834 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17835 {}
17836};
17837
Kailang Yang6dda9f42008-05-27 12:05:31 +020017838static struct hda_verb alc663_g71v_init_verbs[] = {
17839 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17840 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
17841 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
17842
17843 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17844 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17845 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17846
17847 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
17848 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
17849 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
17850 {}
17851};
17852
17853static struct hda_verb alc663_g50v_init_verbs[] = {
17854 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17855 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17856 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17857
17858 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17859 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17860 {}
17861};
17862
Kailang Yangf1d4e282008-08-26 14:03:29 +020017863static struct hda_verb alc662_ecs_init_verbs[] = {
17864 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
17865 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17866 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17867 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17868 {}
17869};
17870
Kailang Yang622e84c2009-04-21 07:39:04 +020017871static struct hda_verb alc272_dell_zm1_init_verbs[] = {
17872 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17873 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17874 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17875 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17876 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17877 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17878 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17879 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17880 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17881 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17882 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17883 {}
17884};
17885
17886static struct hda_verb alc272_dell_init_verbs[] = {
17887 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17888 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17889 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17890 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
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 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17895 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
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
Kailang Yangebb83ee2009-12-17 12:23:00 +010017901static struct hda_verb alc663_mode7_init_verbs[] = {
17902 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17903 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17904 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17905 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17906 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17907 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17908 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
17909 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17910 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17911 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17912 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17913 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17914 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17915 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17916 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17917 {}
17918};
17919
17920static struct hda_verb alc663_mode8_init_verbs[] = {
17921 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17922 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17923 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17924 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
17925 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17926 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17927 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17928 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17929 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17930 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17931 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17932 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17933 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17934 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17935 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17936 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17937 {}
17938};
17939
Kailang Yangf1d4e282008-08-26 14:03:29 +020017940static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
17941 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
17942 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
17943 { } /* end */
17944};
17945
Kailang Yang622e84c2009-04-21 07:39:04 +020017946static struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
17947 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
17948 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
17949 { } /* end */
17950};
17951
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017952static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
17953{
17954 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017955 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017956
Wu Fengguang864f92b2009-11-18 12:38:02 +080017957 present = snd_hda_jack_detect(codec, 0x14);
Takashi Iwai47fd8302007-08-10 17:11:07 +020017958 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080017959
Takashi Iwai47fd8302007-08-10 17:11:07 +020017960 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
17961 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017962}
17963
17964static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
17965{
17966 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017967 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017968
Wu Fengguang864f92b2009-11-18 12:38:02 +080017969 present = snd_hda_jack_detect(codec, 0x1b);
Takashi Iwai47fd8302007-08-10 17:11:07 +020017970 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080017971
Takashi Iwai47fd8302007-08-10 17:11:07 +020017972 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
17973 HDA_AMP_MUTE, bits);
17974 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
17975 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017976}
17977
17978static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
17979 unsigned int res)
17980{
17981 if ((res >> 26) == ALC880_HP_EVENT)
17982 alc662_lenovo_101e_all_automute(codec);
17983 if ((res >> 26) == ALC880_FRONT_EVENT)
17984 alc662_lenovo_101e_ispeaker_automute(codec);
17985}
17986
Kailang Yang291702f2007-10-16 14:28:03 +020017987/* unsolicited event for HP jack sensing */
17988static void alc662_eeepc_unsol_event(struct hda_codec *codec,
17989 unsigned int res)
17990{
Kailang Yang291702f2007-10-16 14:28:03 +020017991 if ((res >> 26) == ALC880_MIC_EVENT)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017992 alc_mic_automute(codec);
Takashi Iwai42171c12009-05-08 14:11:43 +020017993 else
17994 alc262_hippo_unsol_event(codec, res);
Kailang Yang291702f2007-10-16 14:28:03 +020017995}
17996
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017997static void alc662_eeepc_setup(struct hda_codec *codec)
Kailang Yang291702f2007-10-16 14:28:03 +020017998{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017999 struct alc_spec *spec = codec->spec;
18000
18001 alc262_hippo1_setup(codec);
18002 spec->ext_mic.pin = 0x18;
18003 spec->ext_mic.mux_idx = 0;
18004 spec->int_mic.pin = 0x19;
18005 spec->int_mic.mux_idx = 1;
18006 spec->auto_mic = 1;
Kailang Yang291702f2007-10-16 14:28:03 +020018007}
18008
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018009static void alc662_eeepc_inithook(struct hda_codec *codec)
18010{
18011 alc262_hippo_automute(codec);
18012 alc_mic_automute(codec);
18013}
18014
18015static void alc662_eeepc_ep20_setup(struct hda_codec *codec)
Kailang Yang8c427222008-01-10 13:03:59 +010018016{
Takashi Iwai42171c12009-05-08 14:11:43 +020018017 struct alc_spec *spec = codec->spec;
18018
18019 spec->autocfg.hp_pins[0] = 0x14;
18020 spec->autocfg.speaker_pins[0] = 0x1b;
Kailang Yang8c427222008-01-10 13:03:59 +010018021}
18022
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018023#define alc662_eeepc_ep20_inithook alc262_hippo_master_update
18024
Kailang Yang6dda9f42008-05-27 12:05:31 +020018025static void alc663_m51va_speaker_automute(struct hda_codec *codec)
18026{
18027 unsigned int present;
18028 unsigned char bits;
18029
Wu Fengguang864f92b2009-11-18 12:38:02 +080018030 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018031 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yangf1d4e282008-08-26 14:03:29 +020018032 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018033 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018034 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018035 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018036}
18037
18038static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
18039{
18040 unsigned int present;
18041 unsigned char bits;
18042
Wu Fengguang864f92b2009-11-18 12:38:02 +080018043 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018044 bits = present ? HDA_AMP_MUTE : 0;
18045 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018046 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018047 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018048 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018049 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018050 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018051 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018052 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018053}
18054
18055static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
18056{
18057 unsigned int present;
18058 unsigned char bits;
18059
Wu Fengguang864f92b2009-11-18 12:38:02 +080018060 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018061 bits = present ? HDA_AMP_MUTE : 0;
18062 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018063 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018064 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018065 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018066 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018067 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018068 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018069 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018070}
18071
18072static void alc662_f5z_speaker_automute(struct hda_codec *codec)
18073{
18074 unsigned int present;
18075 unsigned char bits;
18076
Wu Fengguang864f92b2009-11-18 12:38:02 +080018077 present = snd_hda_jack_detect(codec, 0x1b);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018078 bits = present ? 0 : PIN_OUT;
18079 snd_hda_codec_write(codec, 0x14, 0,
18080 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
18081}
18082
18083static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
18084{
18085 unsigned int present1, present2;
18086
Wu Fengguang864f92b2009-11-18 12:38:02 +080018087 present1 = snd_hda_jack_detect(codec, 0x21);
18088 present2 = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018089
18090 if (present1 || present2) {
18091 snd_hda_codec_write_cache(codec, 0x14, 0,
18092 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
18093 } else {
18094 snd_hda_codec_write_cache(codec, 0x14, 0,
18095 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
18096 }
18097}
18098
18099static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
18100{
18101 unsigned int present1, present2;
18102
Wu Fengguang864f92b2009-11-18 12:38:02 +080018103 present1 = snd_hda_jack_detect(codec, 0x1b);
18104 present2 = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018105
18106 if (present1 || present2) {
18107 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018108 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018109 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018110 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018111 } else {
18112 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018113 HDA_AMP_MUTE, 0);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018114 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018115 HDA_AMP_MUTE, 0);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018116 }
Kailang Yang6dda9f42008-05-27 12:05:31 +020018117}
18118
Kailang Yangebb83ee2009-12-17 12:23:00 +010018119static void alc663_two_hp_m7_speaker_automute(struct hda_codec *codec)
18120{
18121 unsigned int present1, present2;
18122
18123 present1 = snd_hda_codec_read(codec, 0x1b, 0,
18124 AC_VERB_GET_PIN_SENSE, 0)
18125 & AC_PINSENSE_PRESENCE;
18126 present2 = snd_hda_codec_read(codec, 0x21, 0,
18127 AC_VERB_GET_PIN_SENSE, 0)
18128 & AC_PINSENSE_PRESENCE;
18129
18130 if (present1 || present2) {
18131 snd_hda_codec_write_cache(codec, 0x14, 0,
18132 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
18133 snd_hda_codec_write_cache(codec, 0x17, 0,
18134 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
18135 } else {
18136 snd_hda_codec_write_cache(codec, 0x14, 0,
18137 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
18138 snd_hda_codec_write_cache(codec, 0x17, 0,
18139 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
18140 }
18141}
18142
18143static void alc663_two_hp_m8_speaker_automute(struct hda_codec *codec)
18144{
18145 unsigned int present1, present2;
18146
18147 present1 = snd_hda_codec_read(codec, 0x21, 0,
18148 AC_VERB_GET_PIN_SENSE, 0)
18149 & AC_PINSENSE_PRESENCE;
18150 present2 = snd_hda_codec_read(codec, 0x15, 0,
18151 AC_VERB_GET_PIN_SENSE, 0)
18152 & AC_PINSENSE_PRESENCE;
18153
18154 if (present1 || present2) {
18155 snd_hda_codec_write_cache(codec, 0x14, 0,
18156 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
18157 snd_hda_codec_write_cache(codec, 0x17, 0,
18158 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
18159 } else {
18160 snd_hda_codec_write_cache(codec, 0x14, 0,
18161 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
18162 snd_hda_codec_write_cache(codec, 0x17, 0,
18163 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
18164 }
18165}
18166
Kailang Yang6dda9f42008-05-27 12:05:31 +020018167static void alc663_m51va_unsol_event(struct hda_codec *codec,
18168 unsigned int res)
18169{
18170 switch (res >> 26) {
18171 case ALC880_HP_EVENT:
18172 alc663_m51va_speaker_automute(codec);
18173 break;
18174 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018175 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018176 break;
18177 }
18178}
18179
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018180static void alc663_m51va_setup(struct hda_codec *codec)
18181{
18182 struct alc_spec *spec = codec->spec;
18183 spec->ext_mic.pin = 0x18;
18184 spec->ext_mic.mux_idx = 0;
18185 spec->int_mic.pin = 0x12;
Kailang Yangebb83ee2009-12-17 12:23:00 +010018186 spec->int_mic.mux_idx = 9;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018187 spec->auto_mic = 1;
18188}
18189
Kailang Yang6dda9f42008-05-27 12:05:31 +020018190static void alc663_m51va_inithook(struct hda_codec *codec)
18191{
18192 alc663_m51va_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018193 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018194}
18195
Kailang Yangf1d4e282008-08-26 14:03:29 +020018196/* ***************** Mode1 ******************************/
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018197#define alc663_mode1_unsol_event alc663_m51va_unsol_event
Kailang Yangebb83ee2009-12-17 12:23:00 +010018198
18199static void alc663_mode1_setup(struct hda_codec *codec)
18200{
18201 struct alc_spec *spec = codec->spec;
18202 spec->ext_mic.pin = 0x18;
18203 spec->ext_mic.mux_idx = 0;
18204 spec->int_mic.pin = 0x19;
18205 spec->int_mic.mux_idx = 1;
18206 spec->auto_mic = 1;
18207}
18208
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018209#define alc663_mode1_inithook alc663_m51va_inithook
Kailang Yangf1d4e282008-08-26 14:03:29 +020018210
Kailang Yangf1d4e282008-08-26 14:03:29 +020018211/* ***************** Mode2 ******************************/
18212static void alc662_mode2_unsol_event(struct hda_codec *codec,
18213 unsigned int res)
18214{
18215 switch (res >> 26) {
18216 case ALC880_HP_EVENT:
18217 alc662_f5z_speaker_automute(codec);
18218 break;
18219 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018220 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018221 break;
18222 }
18223}
18224
Kailang Yangebb83ee2009-12-17 12:23:00 +010018225#define alc662_mode2_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018226
Kailang Yangf1d4e282008-08-26 14:03:29 +020018227static void alc662_mode2_inithook(struct hda_codec *codec)
18228{
18229 alc662_f5z_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018230 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018231}
18232/* ***************** Mode3 ******************************/
18233static void alc663_mode3_unsol_event(struct hda_codec *codec,
18234 unsigned int res)
18235{
18236 switch (res >> 26) {
18237 case ALC880_HP_EVENT:
18238 alc663_two_hp_m1_speaker_automute(codec);
18239 break;
18240 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018241 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018242 break;
18243 }
18244}
18245
Kailang Yangebb83ee2009-12-17 12:23:00 +010018246#define alc663_mode3_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018247
Kailang Yangf1d4e282008-08-26 14:03:29 +020018248static void alc663_mode3_inithook(struct hda_codec *codec)
18249{
18250 alc663_two_hp_m1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018251 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018252}
18253/* ***************** Mode4 ******************************/
18254static void alc663_mode4_unsol_event(struct hda_codec *codec,
18255 unsigned int res)
18256{
18257 switch (res >> 26) {
18258 case ALC880_HP_EVENT:
18259 alc663_21jd_two_speaker_automute(codec);
18260 break;
18261 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018262 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018263 break;
18264 }
18265}
18266
Kailang Yangebb83ee2009-12-17 12:23:00 +010018267#define alc663_mode4_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018268
Kailang Yangf1d4e282008-08-26 14:03:29 +020018269static void alc663_mode4_inithook(struct hda_codec *codec)
18270{
18271 alc663_21jd_two_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018272 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018273}
18274/* ***************** Mode5 ******************************/
18275static void alc663_mode5_unsol_event(struct hda_codec *codec,
18276 unsigned int res)
18277{
18278 switch (res >> 26) {
18279 case ALC880_HP_EVENT:
18280 alc663_15jd_two_speaker_automute(codec);
18281 break;
18282 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018283 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018284 break;
18285 }
18286}
18287
Kailang Yangebb83ee2009-12-17 12:23:00 +010018288#define alc663_mode5_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018289
Kailang Yangf1d4e282008-08-26 14:03:29 +020018290static void alc663_mode5_inithook(struct hda_codec *codec)
18291{
18292 alc663_15jd_two_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018293 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018294}
18295/* ***************** Mode6 ******************************/
18296static void alc663_mode6_unsol_event(struct hda_codec *codec,
18297 unsigned int res)
18298{
18299 switch (res >> 26) {
18300 case ALC880_HP_EVENT:
18301 alc663_two_hp_m2_speaker_automute(codec);
18302 break;
18303 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018304 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018305 break;
18306 }
18307}
18308
Kailang Yangebb83ee2009-12-17 12:23:00 +010018309#define alc663_mode6_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018310
Kailang Yangf1d4e282008-08-26 14:03:29 +020018311static void alc663_mode6_inithook(struct hda_codec *codec)
18312{
18313 alc663_two_hp_m2_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018314 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018315}
18316
Kailang Yangebb83ee2009-12-17 12:23:00 +010018317/* ***************** Mode7 ******************************/
18318static void alc663_mode7_unsol_event(struct hda_codec *codec,
18319 unsigned int res)
18320{
18321 switch (res >> 26) {
18322 case ALC880_HP_EVENT:
18323 alc663_two_hp_m7_speaker_automute(codec);
18324 break;
18325 case ALC880_MIC_EVENT:
18326 alc_mic_automute(codec);
18327 break;
18328 }
18329}
18330
18331#define alc663_mode7_setup alc663_mode1_setup
18332
18333static void alc663_mode7_inithook(struct hda_codec *codec)
18334{
18335 alc663_two_hp_m7_speaker_automute(codec);
18336 alc_mic_automute(codec);
18337}
18338
18339/* ***************** Mode8 ******************************/
18340static void alc663_mode8_unsol_event(struct hda_codec *codec,
18341 unsigned int res)
18342{
18343 switch (res >> 26) {
18344 case ALC880_HP_EVENT:
18345 alc663_two_hp_m8_speaker_automute(codec);
18346 break;
18347 case ALC880_MIC_EVENT:
18348 alc_mic_automute(codec);
18349 break;
18350 }
18351}
18352
18353#define alc663_mode8_setup alc663_m51va_setup
18354
18355static void alc663_mode8_inithook(struct hda_codec *codec)
18356{
18357 alc663_two_hp_m8_speaker_automute(codec);
18358 alc_mic_automute(codec);
18359}
18360
Kailang Yang6dda9f42008-05-27 12:05:31 +020018361static void alc663_g71v_hp_automute(struct hda_codec *codec)
18362{
18363 unsigned int present;
18364 unsigned char bits;
18365
Wu Fengguang864f92b2009-11-18 12:38:02 +080018366 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018367 bits = present ? HDA_AMP_MUTE : 0;
18368 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
18369 HDA_AMP_MUTE, bits);
18370 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
18371 HDA_AMP_MUTE, bits);
18372}
18373
18374static void alc663_g71v_front_automute(struct hda_codec *codec)
18375{
18376 unsigned int present;
18377 unsigned char bits;
18378
Wu Fengguang864f92b2009-11-18 12:38:02 +080018379 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018380 bits = present ? HDA_AMP_MUTE : 0;
18381 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
18382 HDA_AMP_MUTE, bits);
18383}
18384
18385static void alc663_g71v_unsol_event(struct hda_codec *codec,
18386 unsigned int res)
18387{
18388 switch (res >> 26) {
18389 case ALC880_HP_EVENT:
18390 alc663_g71v_hp_automute(codec);
18391 break;
18392 case ALC880_FRONT_EVENT:
18393 alc663_g71v_front_automute(codec);
18394 break;
18395 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018396 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018397 break;
18398 }
18399}
18400
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018401#define alc663_g71v_setup alc663_m51va_setup
18402
Kailang Yang6dda9f42008-05-27 12:05:31 +020018403static void alc663_g71v_inithook(struct hda_codec *codec)
18404{
18405 alc663_g71v_front_automute(codec);
18406 alc663_g71v_hp_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018407 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018408}
18409
18410static void alc663_g50v_unsol_event(struct hda_codec *codec,
18411 unsigned int res)
18412{
18413 switch (res >> 26) {
18414 case ALC880_HP_EVENT:
18415 alc663_m51va_speaker_automute(codec);
18416 break;
18417 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018418 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018419 break;
18420 }
18421}
18422
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018423#define alc663_g50v_setup alc663_m51va_setup
18424
Kailang Yang6dda9f42008-05-27 12:05:31 +020018425static void alc663_g50v_inithook(struct hda_codec *codec)
18426{
18427 alc663_m51va_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018428 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018429}
18430
Kailang Yangf1d4e282008-08-26 14:03:29 +020018431static struct snd_kcontrol_new alc662_ecs_mixer[] = {
18432 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020018433 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018434
18435 HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT),
18436 HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
18437 HDA_CODEC_MUTE("e-Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
18438
18439 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
18440 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
18441 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
18442 { } /* end */
18443};
18444
Chris Pockelé9541ba12009-05-12 08:08:53 +020018445static struct snd_kcontrol_new alc272_nc10_mixer[] = {
18446 /* Master Playback automatically created from Speaker and Headphone */
18447 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
18448 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
18449 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
18450 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
18451
18452 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
18453 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
18454 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
18455
18456 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
18457 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
18458 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
18459 { } /* end */
18460};
18461
Takashi Iwaicb53c622007-08-10 17:21:45 +020018462#ifdef CONFIG_SND_HDA_POWER_SAVE
18463#define alc662_loopbacks alc880_loopbacks
18464#endif
18465
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018466
Sasha Alexandrdef319f2009-06-16 16:00:15 -040018467/* pcm configuration: identical with ALC880 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018468#define alc662_pcm_analog_playback alc880_pcm_analog_playback
18469#define alc662_pcm_analog_capture alc880_pcm_analog_capture
18470#define alc662_pcm_digital_playback alc880_pcm_digital_playback
18471#define alc662_pcm_digital_capture alc880_pcm_digital_capture
18472
18473/*
18474 * configuration and preset
18475 */
18476static const char *alc662_models[ALC662_MODEL_LAST] = {
18477 [ALC662_3ST_2ch_DIG] = "3stack-dig",
18478 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
18479 [ALC662_3ST_6ch] = "3stack-6ch",
18480 [ALC662_5ST_DIG] = "6stack-dig",
18481 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020018482 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010018483 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangf1d4e282008-08-26 14:03:29 +020018484 [ALC662_ECS] = "ecs",
Kailang Yang6dda9f42008-05-27 12:05:31 +020018485 [ALC663_ASUS_M51VA] = "m51va",
18486 [ALC663_ASUS_G71V] = "g71v",
18487 [ALC663_ASUS_H13] = "h13",
18488 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangf1d4e282008-08-26 14:03:29 +020018489 [ALC663_ASUS_MODE1] = "asus-mode1",
18490 [ALC662_ASUS_MODE2] = "asus-mode2",
18491 [ALC663_ASUS_MODE3] = "asus-mode3",
18492 [ALC663_ASUS_MODE4] = "asus-mode4",
18493 [ALC663_ASUS_MODE5] = "asus-mode5",
18494 [ALC663_ASUS_MODE6] = "asus-mode6",
Kailang Yangebb83ee2009-12-17 12:23:00 +010018495 [ALC663_ASUS_MODE7] = "asus-mode7",
18496 [ALC663_ASUS_MODE8] = "asus-mode8",
Takashi Iwai01f2bd42009-05-11 08:12:43 +020018497 [ALC272_DELL] = "dell",
18498 [ALC272_DELL_ZM1] = "dell-zm1",
Chris Pockelé9541ba12009-05-12 08:08:53 +020018499 [ALC272_SAMSUNG_NC10] = "samsung-nc10",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018500 [ALC662_AUTO] = "auto",
18501};
18502
18503static struct snd_pci_quirk alc662_cfg_tbl[] = {
Takashi Iwaidea0a502009-02-09 17:14:52 +010018504 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
Kailang Yang622e84c2009-04-21 07:39:04 +020018505 SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
18506 SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018507 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
18508 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
Kailang Yangcec27c82010-02-04 14:18:18 +010018509 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018510 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
18511 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
18512 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
18513 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018514 SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC663_ASUS_MODE1),
18515 SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018516 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018517 SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC663_ASUS_MODE7),
18518 SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC663_ASUS_MODE7),
18519 SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC663_ASUS_MODE8),
18520 SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC663_ASUS_MODE3),
18521 SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018522 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018523 SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_ASUS_MODE2),
18524 SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018525 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
18526 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
18527 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
18528 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018529 SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020018530 SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3),
18531 SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA),
18532 SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018533 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
18534 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
18535 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
18536 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018537 SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018538 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
18539 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang6dda9f42008-05-27 12:05:31 +020018540 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018541 /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/
18542 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
18543 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020018544 SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1),
Kailang Yangcec27c82010-02-04 14:18:18 +010018545 SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020018546 SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1),
18547 SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018548 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
18549 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
18550 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018551 SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018552 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
18553 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020018554 SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018555 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
Kailang Yang80ffe862008-10-15 11:23:27 +020018556 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018557 /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/
18558 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
18559 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018560 SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018561 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
18562 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010018563 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020018564 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010018565 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018566 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
Herton Ronaldo Krzesinski95fe5f22008-09-26 23:48:45 -030018567 SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
18568 ALC662_3ST_6ch_DIG),
Takashi Iwai4dee8ba2010-01-13 17:20:08 +010018569 SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO),
Chris Pockelé9541ba12009-05-12 08:08:53 +020018570 SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
Herton Ronaldo Krzesinskicb559742008-09-26 23:47:45 -030018571 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
18572 ALC662_3ST_6ch_DIG),
Kailang Yang6227cdc2010-02-25 08:36:52 +010018573 SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13),
Vedran Miletic19c009a2008-09-29 20:29:25 +020018574 SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
Takashi Iwai5bd37292009-04-21 18:36:30 +020018575 SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018576 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Takashi Iwai238713d2008-10-05 10:57:39 +020018577 SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
Vedran Miletic19c009a2008-09-29 20:29:25 +020018578 ALC662_3ST_6ch_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018579 SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
18580 ALC663_ASUS_H13),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018581 {}
18582};
18583
18584static struct alc_config_preset alc662_presets[] = {
18585 [ALC662_3ST_2ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018586 .mixers = { alc662_3ST_2ch_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018587 .init_verbs = { alc662_init_verbs },
18588 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18589 .dac_nids = alc662_dac_nids,
18590 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018591 .dig_in_nid = ALC662_DIGIN_NID,
18592 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18593 .channel_mode = alc662_3ST_2ch_modes,
18594 .input_mux = &alc662_capture_source,
18595 },
18596 [ALC662_3ST_6ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018597 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018598 .init_verbs = { alc662_init_verbs },
18599 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18600 .dac_nids = alc662_dac_nids,
18601 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018602 .dig_in_nid = ALC662_DIGIN_NID,
18603 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18604 .channel_mode = alc662_3ST_6ch_modes,
18605 .need_dac_fix = 1,
18606 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018607 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018608 [ALC662_3ST_6ch] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018609 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018610 .init_verbs = { alc662_init_verbs },
18611 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18612 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018613 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18614 .channel_mode = alc662_3ST_6ch_modes,
18615 .need_dac_fix = 1,
18616 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018617 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018618 [ALC662_5ST_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018619 .mixers = { alc662_base_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018620 .init_verbs = { alc662_init_verbs },
18621 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18622 .dac_nids = alc662_dac_nids,
18623 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018624 .dig_in_nid = ALC662_DIGIN_NID,
18625 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
18626 .channel_mode = alc662_5stack_modes,
18627 .input_mux = &alc662_capture_source,
18628 },
18629 [ALC662_LENOVO_101E] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018630 .mixers = { alc662_lenovo_101e_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018631 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
18632 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18633 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018634 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18635 .channel_mode = alc662_3ST_2ch_modes,
18636 .input_mux = &alc662_lenovo_101e_capture_source,
18637 .unsol_event = alc662_lenovo_101e_unsol_event,
18638 .init_hook = alc662_lenovo_101e_all_automute,
18639 },
Kailang Yang291702f2007-10-16 14:28:03 +020018640 [ALC662_ASUS_EEEPC_P701] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018641 .mixers = { alc662_eeepc_p701_mixer },
Kailang Yang291702f2007-10-16 14:28:03 +020018642 .init_verbs = { alc662_init_verbs,
18643 alc662_eeepc_sue_init_verbs },
18644 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18645 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020018646 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18647 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang291702f2007-10-16 14:28:03 +020018648 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018649 .setup = alc662_eeepc_setup,
Kailang Yang291702f2007-10-16 14:28:03 +020018650 .init_hook = alc662_eeepc_inithook,
18651 },
Kailang Yang8c427222008-01-10 13:03:59 +010018652 [ALC662_ASUS_EEEPC_EP20] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018653 .mixers = { alc662_eeepc_ep20_mixer,
Kailang Yang8c427222008-01-10 13:03:59 +010018654 alc662_chmode_mixer },
18655 .init_verbs = { alc662_init_verbs,
18656 alc662_eeepc_ep20_sue_init_verbs },
18657 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18658 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010018659 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18660 .channel_mode = alc662_3ST_6ch_modes,
18661 .input_mux = &alc662_lenovo_101e_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020018662 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018663 .setup = alc662_eeepc_ep20_setup,
Kailang Yang8c427222008-01-10 13:03:59 +010018664 .init_hook = alc662_eeepc_ep20_inithook,
18665 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018666 [ALC662_ECS] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018667 .mixers = { alc662_ecs_mixer },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018668 .init_verbs = { alc662_init_verbs,
18669 alc662_ecs_init_verbs },
18670 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18671 .dac_nids = alc662_dac_nids,
18672 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18673 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018674 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018675 .setup = alc662_eeepc_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018676 .init_hook = alc662_eeepc_inithook,
18677 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018678 [ALC663_ASUS_M51VA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018679 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018680 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
18681 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18682 .dac_nids = alc662_dac_nids,
18683 .dig_out_nid = ALC662_DIGOUT_NID,
18684 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18685 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018686 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018687 .setup = alc663_m51va_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018688 .init_hook = alc663_m51va_inithook,
18689 },
18690 [ALC663_ASUS_G71V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018691 .mixers = { alc663_g71v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018692 .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
18693 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18694 .dac_nids = alc662_dac_nids,
18695 .dig_out_nid = ALC662_DIGOUT_NID,
18696 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18697 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018698 .unsol_event = alc663_g71v_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018699 .setup = alc663_g71v_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018700 .init_hook = alc663_g71v_inithook,
18701 },
18702 [ALC663_ASUS_H13] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018703 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018704 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
18705 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18706 .dac_nids = alc662_dac_nids,
18707 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18708 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018709 .unsol_event = alc663_m51va_unsol_event,
18710 .init_hook = alc663_m51va_inithook,
18711 },
18712 [ALC663_ASUS_G50V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018713 .mixers = { alc663_g50v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018714 .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
18715 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18716 .dac_nids = alc662_dac_nids,
18717 .dig_out_nid = ALC662_DIGOUT_NID,
18718 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18719 .channel_mode = alc662_3ST_6ch_modes,
18720 .input_mux = &alc663_capture_source,
18721 .unsol_event = alc663_g50v_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018722 .setup = alc663_g50v_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018723 .init_hook = alc663_g50v_inithook,
18724 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018725 [ALC663_ASUS_MODE1] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018726 .mixers = { alc663_m51va_mixer },
18727 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018728 .init_verbs = { alc662_init_verbs,
18729 alc663_21jd_amic_init_verbs },
18730 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18731 .hp_nid = 0x03,
18732 .dac_nids = alc662_dac_nids,
18733 .dig_out_nid = ALC662_DIGOUT_NID,
18734 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18735 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018736 .unsol_event = alc663_mode1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018737 .setup = alc663_mode1_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018738 .init_hook = alc663_mode1_inithook,
18739 },
18740 [ALC662_ASUS_MODE2] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018741 .mixers = { alc662_1bjd_mixer },
18742 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018743 .init_verbs = { alc662_init_verbs,
18744 alc662_1bjd_amic_init_verbs },
18745 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18746 .dac_nids = alc662_dac_nids,
18747 .dig_out_nid = ALC662_DIGOUT_NID,
18748 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18749 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018750 .unsol_event = alc662_mode2_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018751 .setup = alc662_mode2_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018752 .init_hook = alc662_mode2_inithook,
18753 },
18754 [ALC663_ASUS_MODE3] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018755 .mixers = { alc663_two_hp_m1_mixer },
18756 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018757 .init_verbs = { alc662_init_verbs,
18758 alc663_two_hp_amic_m1_init_verbs },
18759 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18760 .hp_nid = 0x03,
18761 .dac_nids = alc662_dac_nids,
18762 .dig_out_nid = ALC662_DIGOUT_NID,
18763 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18764 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018765 .unsol_event = alc663_mode3_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018766 .setup = alc663_mode3_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018767 .init_hook = alc663_mode3_inithook,
18768 },
18769 [ALC663_ASUS_MODE4] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018770 .mixers = { alc663_asus_21jd_clfe_mixer },
18771 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018772 .init_verbs = { alc662_init_verbs,
18773 alc663_21jd_amic_init_verbs},
18774 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18775 .hp_nid = 0x03,
18776 .dac_nids = alc662_dac_nids,
18777 .dig_out_nid = ALC662_DIGOUT_NID,
18778 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18779 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018780 .unsol_event = alc663_mode4_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018781 .setup = alc663_mode4_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018782 .init_hook = alc663_mode4_inithook,
18783 },
18784 [ALC663_ASUS_MODE5] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018785 .mixers = { alc663_asus_15jd_clfe_mixer },
18786 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018787 .init_verbs = { alc662_init_verbs,
18788 alc663_15jd_amic_init_verbs },
18789 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18790 .hp_nid = 0x03,
18791 .dac_nids = alc662_dac_nids,
18792 .dig_out_nid = ALC662_DIGOUT_NID,
18793 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18794 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018795 .unsol_event = alc663_mode5_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018796 .setup = alc663_mode5_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018797 .init_hook = alc663_mode5_inithook,
18798 },
18799 [ALC663_ASUS_MODE6] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018800 .mixers = { alc663_two_hp_m2_mixer },
18801 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018802 .init_verbs = { alc662_init_verbs,
18803 alc663_two_hp_amic_m2_init_verbs },
18804 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18805 .hp_nid = 0x03,
18806 .dac_nids = alc662_dac_nids,
18807 .dig_out_nid = ALC662_DIGOUT_NID,
18808 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18809 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018810 .unsol_event = alc663_mode6_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018811 .setup = alc663_mode6_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018812 .init_hook = alc663_mode6_inithook,
18813 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010018814 [ALC663_ASUS_MODE7] = {
18815 .mixers = { alc663_mode7_mixer },
18816 .cap_mixer = alc662_auto_capture_mixer,
18817 .init_verbs = { alc662_init_verbs,
18818 alc663_mode7_init_verbs },
18819 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18820 .hp_nid = 0x03,
18821 .dac_nids = alc662_dac_nids,
18822 .dig_out_nid = ALC662_DIGOUT_NID,
18823 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18824 .channel_mode = alc662_3ST_2ch_modes,
18825 .unsol_event = alc663_mode7_unsol_event,
18826 .setup = alc663_mode7_setup,
18827 .init_hook = alc663_mode7_inithook,
18828 },
18829 [ALC663_ASUS_MODE8] = {
18830 .mixers = { alc663_mode8_mixer },
18831 .cap_mixer = alc662_auto_capture_mixer,
18832 .init_verbs = { alc662_init_verbs,
18833 alc663_mode8_init_verbs },
18834 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18835 .hp_nid = 0x03,
18836 .dac_nids = alc662_dac_nids,
18837 .dig_out_nid = ALC662_DIGOUT_NID,
18838 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18839 .channel_mode = alc662_3ST_2ch_modes,
18840 .unsol_event = alc663_mode8_unsol_event,
18841 .setup = alc663_mode8_setup,
18842 .init_hook = alc663_mode8_inithook,
18843 },
Kailang Yang622e84c2009-04-21 07:39:04 +020018844 [ALC272_DELL] = {
18845 .mixers = { alc663_m51va_mixer },
18846 .cap_mixer = alc272_auto_capture_mixer,
18847 .init_verbs = { alc662_init_verbs, alc272_dell_init_verbs },
18848 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18849 .dac_nids = alc662_dac_nids,
18850 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18851 .adc_nids = alc272_adc_nids,
18852 .num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
18853 .capsrc_nids = alc272_capsrc_nids,
18854 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang622e84c2009-04-21 07:39:04 +020018855 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018856 .setup = alc663_m51va_setup,
Kailang Yang622e84c2009-04-21 07:39:04 +020018857 .init_hook = alc663_m51va_inithook,
18858 },
18859 [ALC272_DELL_ZM1] = {
18860 .mixers = { alc663_m51va_mixer },
18861 .cap_mixer = alc662_auto_capture_mixer,
18862 .init_verbs = { alc662_init_verbs, alc272_dell_zm1_init_verbs },
18863 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18864 .dac_nids = alc662_dac_nids,
18865 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18866 .adc_nids = alc662_adc_nids,
Takashi Iwaib59bdf32009-08-11 09:47:30 +020018867 .num_adc_nids = 1,
Kailang Yang622e84c2009-04-21 07:39:04 +020018868 .capsrc_nids = alc662_capsrc_nids,
18869 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang622e84c2009-04-21 07:39:04 +020018870 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018871 .setup = alc663_m51va_setup,
Kailang Yang622e84c2009-04-21 07:39:04 +020018872 .init_hook = alc663_m51va_inithook,
18873 },
Chris Pockelé9541ba12009-05-12 08:08:53 +020018874 [ALC272_SAMSUNG_NC10] = {
18875 .mixers = { alc272_nc10_mixer },
18876 .init_verbs = { alc662_init_verbs,
18877 alc663_21jd_amic_init_verbs },
18878 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18879 .dac_nids = alc272_dac_nids,
18880 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18881 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018882 /*.input_mux = &alc272_nc10_capture_source,*/
Chris Pockelé9541ba12009-05-12 08:08:53 +020018883 .unsol_event = alc663_mode4_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018884 .setup = alc663_mode4_setup,
Chris Pockelé9541ba12009-05-12 08:08:53 +020018885 .init_hook = alc663_mode4_inithook,
18886 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018887};
18888
18889
18890/*
18891 * BIOS auto configuration
18892 */
18893
Takashi Iwai7085ec12009-10-02 09:03:58 +020018894/* convert from MIX nid to DAC */
18895static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid)
18896{
18897 if (nid == 0x0f)
18898 return 0x02;
18899 else if (nid >= 0x0c && nid <= 0x0e)
18900 return nid - 0x0c + 0x02;
18901 else
18902 return 0;
18903}
18904
18905/* get MIX nid connected to the given pin targeted to DAC */
18906static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
18907 hda_nid_t dac)
18908{
18909 hda_nid_t mix[4];
18910 int i, num;
18911
18912 num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
18913 for (i = 0; i < num; i++) {
18914 if (alc662_mix_to_dac(mix[i]) == dac)
18915 return mix[i];
18916 }
18917 return 0;
18918}
18919
18920/* look for an empty DAC slot */
18921static hda_nid_t alc662_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
18922{
18923 struct alc_spec *spec = codec->spec;
18924 hda_nid_t srcs[5];
18925 int i, j, num;
18926
18927 num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
18928 if (num < 0)
18929 return 0;
18930 for (i = 0; i < num; i++) {
18931 hda_nid_t nid = alc662_mix_to_dac(srcs[i]);
18932 if (!nid)
18933 continue;
18934 for (j = 0; j < spec->multiout.num_dacs; j++)
18935 if (spec->multiout.dac_nids[j] == nid)
18936 break;
18937 if (j >= spec->multiout.num_dacs)
18938 return nid;
18939 }
18940 return 0;
18941}
18942
18943/* fill in the dac_nids table from the parsed pin configuration */
18944static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
18945 const struct auto_pin_cfg *cfg)
18946{
18947 struct alc_spec *spec = codec->spec;
18948 int i;
18949 hda_nid_t dac;
18950
18951 spec->multiout.dac_nids = spec->private_dac_nids;
18952 for (i = 0; i < cfg->line_outs; i++) {
18953 dac = alc662_look_for_dac(codec, cfg->line_out_pins[i]);
18954 if (!dac)
18955 continue;
18956 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
18957 }
18958 return 0;
18959}
18960
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018961static inline int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018962 hda_nid_t nid, unsigned int chs)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018963{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018964 return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018965 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
18966}
18967
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018968static inline int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018969 hda_nid_t nid, unsigned int chs)
18970{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018971 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018972 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
18973}
18974
18975#define alc662_add_stereo_vol(spec, pfx, nid) \
18976 alc662_add_vol_ctl(spec, pfx, nid, 3)
18977#define alc662_add_stereo_sw(spec, pfx, nid) \
18978 alc662_add_sw_ctl(spec, pfx, nid, 3)
18979
18980/* add playback controls from the parsed DAC table */
18981static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
18982 const struct auto_pin_cfg *cfg)
18983{
18984 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018985 static const char *chname[4] = {
18986 "Front", "Surround", NULL /*CLFE*/, "Side"
18987 };
Takashi Iwai7085ec12009-10-02 09:03:58 +020018988 hda_nid_t nid, mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018989 int i, err;
18990
18991 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020018992 nid = spec->multiout.dac_nids[i];
18993 if (!nid)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018994 continue;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018995 mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid);
18996 if (!mix)
18997 continue;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018998 if (i == 2) {
18999 /* Center/LFE */
Takashi Iwai7085ec12009-10-02 09:03:58 +020019000 err = alc662_add_vol_ctl(spec, "Center", nid, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019001 if (err < 0)
19002 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019003 err = alc662_add_vol_ctl(spec, "LFE", nid, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019004 if (err < 0)
19005 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019006 err = alc662_add_sw_ctl(spec, "Center", mix, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019007 if (err < 0)
19008 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019009 err = alc662_add_sw_ctl(spec, "LFE", mix, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019010 if (err < 0)
19011 return err;
19012 } else {
Takashi Iwai0d884cb2009-08-25 16:14:35 +020019013 const char *pfx;
19014 if (cfg->line_outs == 1 &&
19015 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020019016 if (cfg->hp_outs)
Takashi Iwai0d884cb2009-08-25 16:14:35 +020019017 pfx = "Speaker";
19018 else
19019 pfx = "PCM";
19020 } else
19021 pfx = chname[i];
Takashi Iwai7085ec12009-10-02 09:03:58 +020019022 err = alc662_add_vol_ctl(spec, pfx, nid, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019023 if (err < 0)
19024 return err;
Takashi Iwai0d884cb2009-08-25 16:14:35 +020019025 if (cfg->line_outs == 1 &&
19026 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
19027 pfx = "Speaker";
Takashi Iwai7085ec12009-10-02 09:03:58 +020019028 err = alc662_add_sw_ctl(spec, pfx, mix, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019029 if (err < 0)
19030 return err;
19031 }
19032 }
19033 return 0;
19034}
19035
19036/* add playback controls for speaker and HP outputs */
Takashi Iwai7085ec12009-10-02 09:03:58 +020019037/* return DAC nid if any new DAC is assigned */
19038static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019039 const char *pfx)
19040{
Takashi Iwai7085ec12009-10-02 09:03:58 +020019041 struct alc_spec *spec = codec->spec;
19042 hda_nid_t nid, mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019043 int err;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019044
19045 if (!pin)
19046 return 0;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019047 nid = alc662_look_for_dac(codec, pin);
19048 if (!nid) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020019049 /* the corresponding DAC is already occupied */
19050 if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
19051 return 0; /* no way */
19052 /* create a switch only */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020019053 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019054 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
19055 }
19056
19057 mix = alc662_dac_to_mix(codec, pin, nid);
19058 if (!mix)
19059 return 0;
19060 err = alc662_add_vol_ctl(spec, pfx, nid, 3);
19061 if (err < 0)
Takashi Iwai24fb9172008-09-02 14:48:20 +020019062 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019063 err = alc662_add_sw_ctl(spec, pfx, mix, 3);
19064 if (err < 0)
19065 return err;
19066 return nid;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019067}
19068
19069/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020019070#define alc662_auto_create_input_ctls \
Takashi Iwai4b7348a2009-10-14 18:25:23 +020019071 alc882_auto_create_input_ctls
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019072
19073static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
19074 hda_nid_t nid, int pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019075 hda_nid_t dac)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019076{
Takashi Iwai7085ec12009-10-02 09:03:58 +020019077 int i, num;
Takashi Iwaice503f32010-07-30 10:37:29 +020019078 hda_nid_t srcs[HDA_MAX_CONNECTIONS];
Takashi Iwai7085ec12009-10-02 09:03:58 +020019079
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019080 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019081 /* need the manual connection? */
Takashi Iwai7085ec12009-10-02 09:03:58 +020019082 num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
19083 if (num <= 1)
19084 return;
19085 for (i = 0; i < num; i++) {
19086 if (alc662_mix_to_dac(srcs[i]) != dac)
19087 continue;
19088 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
19089 return;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019090 }
19091}
19092
19093static void alc662_auto_init_multi_out(struct hda_codec *codec)
19094{
19095 struct alc_spec *spec = codec->spec;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019096 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019097 int i;
19098
19099 for (i = 0; i <= HDA_SIDE; i++) {
19100 hda_nid_t nid = spec->autocfg.line_out_pins[i];
19101 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020019102 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019103 spec->multiout.dac_nids[i]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019104 }
19105}
19106
19107static void alc662_auto_init_hp_out(struct hda_codec *codec)
19108{
19109 struct alc_spec *spec = codec->spec;
19110 hda_nid_t pin;
19111
19112 pin = spec->autocfg.hp_pins[0];
Takashi Iwai7085ec12009-10-02 09:03:58 +020019113 if (pin)
19114 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP,
19115 spec->multiout.hp_nid);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019116 pin = spec->autocfg.speaker_pins[0];
19117 if (pin)
Takashi Iwai7085ec12009-10-02 09:03:58 +020019118 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT,
19119 spec->multiout.extra_out_nid[0]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019120}
19121
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019122#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
19123
19124static void alc662_auto_init_analog_input(struct hda_codec *codec)
19125{
19126 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019127 struct auto_pin_cfg *cfg = &spec->autocfg;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019128 int i;
19129
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019130 for (i = 0; i < cfg->num_inputs; i++) {
19131 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +020019132 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai30ea0982010-09-16 18:47:56 +020019133 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwai52ca15b2009-03-23 12:51:55 +010019134 if (nid != ALC662_PIN_CD_NID &&
Takashi Iwaie82c0252009-03-23 15:17:38 +010019135 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019136 snd_hda_codec_write(codec, nid, 0,
19137 AC_VERB_SET_AMP_GAIN_MUTE,
19138 AMP_OUT_MUTE);
19139 }
19140 }
19141}
19142
Takashi Iwaif511b012008-08-15 16:46:42 +020019143#define alc662_auto_init_input_src alc882_auto_init_input_src
19144
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019145static int alc662_parse_auto_config(struct hda_codec *codec)
19146{
19147 struct alc_spec *spec = codec->spec;
19148 int err;
19149 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
19150
19151 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
19152 alc662_ignore);
19153 if (err < 0)
19154 return err;
19155 if (!spec->autocfg.line_outs)
19156 return 0; /* can't find valid BIOS pin config */
19157
Takashi Iwai7085ec12009-10-02 09:03:58 +020019158 err = alc662_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019159 if (err < 0)
19160 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019161 err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019162 if (err < 0)
19163 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019164 err = alc662_auto_create_extra_out(codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019165 spec->autocfg.speaker_pins[0],
19166 "Speaker");
19167 if (err < 0)
19168 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019169 if (err)
19170 spec->multiout.extra_out_nid[0] = err;
19171 err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019172 "Headphone");
19173 if (err < 0)
19174 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019175 if (err)
19176 spec->multiout.hp_nid = err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020019177 err = alc662_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019178 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019179 return err;
19180
19181 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
19182
Takashi Iwai757899a2010-07-30 10:48:14 +020019183 alc_auto_parse_digital(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019184
Takashi Iwai603c4012008-07-30 15:01:44 +020019185 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010019186 add_mixer(spec, spec->kctls.list);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019187
19188 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020019189 spec->input_mux = &spec->private_imux[0];
Kailang Yangea1fb292008-08-26 12:58:38 +020019190
Kailang Yangcec27c82010-02-04 14:18:18 +010019191 add_verb(spec, alc662_init_verbs);
19192 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019193 codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
Kailang Yangcec27c82010-02-04 14:18:18 +010019194 add_verb(spec, alc663_init_verbs);
19195
19196 if (codec->vendor_id == 0x10ec0272)
19197 add_verb(spec, alc272_init_verbs);
Takashi Iwaiee979a142008-09-02 15:42:20 +020019198
19199 err = alc_auto_add_mic_boost(codec);
19200 if (err < 0)
19201 return err;
19202
Kailang Yang6227cdc2010-02-25 08:36:52 +010019203 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
19204 codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
19205 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0x21);
19206 else
19207 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020019208
Takashi Iwai8c87286f2007-06-19 12:11:16 +020019209 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019210}
19211
19212/* additional initialization for auto-configuration model */
19213static void alc662_auto_init(struct hda_codec *codec)
19214{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019215 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019216 alc662_auto_init_multi_out(codec);
19217 alc662_auto_init_hp_out(codec);
19218 alc662_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020019219 alc662_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020019220 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019221 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020019222 alc_inithook(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019223}
19224
David Henningsson6cb3b702010-09-09 08:51:44 +020019225enum {
19226 ALC662_FIXUP_IDEAPAD,
19227};
19228
19229static const struct alc_fixup alc662_fixups[] = {
19230 [ALC662_FIXUP_IDEAPAD] = {
19231 .pins = (const struct alc_pincfg[]) {
19232 { 0x17, 0x99130112 }, /* subwoofer */
19233 { }
19234 }
19235 },
19236};
19237
19238static struct snd_pci_quirk alc662_fixup_tbl[] = {
19239 SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
19240 {}
19241};
19242
19243
19244
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019245static int patch_alc662(struct hda_codec *codec)
19246{
19247 struct alc_spec *spec;
19248 int err, board_config;
19249
19250 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
19251 if (!spec)
19252 return -ENOMEM;
19253
19254 codec->spec = spec;
19255
Kailang Yangda00c242010-03-19 11:23:45 +010019256 alc_auto_parse_customize_define(codec);
19257
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020019258 alc_fix_pll_init(codec, 0x20, 0x04, 15);
19259
Kailang Yangc027ddc2010-03-19 11:33:06 +010019260 if (alc_read_coef_idx(codec, 0) == 0x8020)
19261 alc_codec_rename(codec, "ALC661");
19262 else if ((alc_read_coef_idx(codec, 0) & (1 << 14)) &&
19263 codec->bus->pci->subsystem_vendor == 0x1025 &&
19264 spec->cdefine.platform_type == 1)
19265 alc_codec_rename(codec, "ALC272X");
Kailang Yang274693f2009-12-03 10:07:50 +010019266
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019267 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
19268 alc662_models,
19269 alc662_cfg_tbl);
19270 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020019271 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
19272 codec->chip_name);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019273 board_config = ALC662_AUTO;
19274 }
19275
19276 if (board_config == ALC662_AUTO) {
David Henningsson6cb3b702010-09-09 08:51:44 +020019277 alc_pick_fixup(codec, alc662_fixup_tbl, alc662_fixups, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019278 /* automatic parse from the BIOS config */
19279 err = alc662_parse_auto_config(codec);
19280 if (err < 0) {
19281 alc_free(codec);
19282 return err;
Takashi Iwai8c87286f2007-06-19 12:11:16 +020019283 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019284 printk(KERN_INFO
19285 "hda_codec: Cannot set up configuration "
19286 "from BIOS. Using base mode...\n");
19287 board_config = ALC662_3ST_2ch_DIG;
19288 }
19289 }
19290
Takashi Iwaidc1eae22010-07-29 15:30:02 +020019291 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020019292 err = snd_hda_attach_beep_device(codec, 0x1);
19293 if (err < 0) {
19294 alc_free(codec);
19295 return err;
19296 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090019297 }
19298
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019299 if (board_config != ALC662_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020019300 setup_preset(codec, &alc662_presets[board_config]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019301
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019302 spec->stream_analog_playback = &alc662_pcm_analog_playback;
19303 spec->stream_analog_capture = &alc662_pcm_analog_capture;
19304
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019305 spec->stream_digital_playback = &alc662_pcm_digital_playback;
19306 spec->stream_digital_capture = &alc662_pcm_digital_capture;
19307
Takashi Iwaidd704692009-08-11 08:45:11 +020019308 if (!spec->adc_nids) {
19309 spec->adc_nids = alc662_adc_nids;
19310 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
19311 }
19312 if (!spec->capsrc_nids)
19313 spec->capsrc_nids = alc662_capsrc_nids;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019314
Takashi Iwaif9e336f2008-10-31 16:37:07 +010019315 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020019316 set_capture_mixer(codec);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010019317
Takashi Iwaidc1eae22010-07-29 15:30:02 +020019318 if (has_cdefine_beep(codec)) {
Kailang Yangda00c242010-03-19 11:23:45 +010019319 switch (codec->vendor_id) {
19320 case 0x10ec0662:
19321 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
19322 break;
19323 case 0x10ec0272:
19324 case 0x10ec0663:
19325 case 0x10ec0665:
19326 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
19327 break;
19328 case 0x10ec0273:
19329 set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
19330 break;
19331 }
Kailang Yangcec27c82010-02-04 14:18:18 +010019332 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010019333 spec->vmaster_nid = 0x02;
19334
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019335 codec->patch_ops = alc_patch_ops;
David Henningsson6cb3b702010-09-09 08:51:44 +020019336 if (board_config == ALC662_AUTO) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019337 spec->init_hook = alc662_auto_init;
David Henningsson6cb3b702010-09-09 08:51:44 +020019338 alc_pick_fixup(codec, alc662_fixup_tbl, alc662_fixups, 0);
19339 }
19340
Takashi Iwaicb53c622007-08-10 17:21:45 +020019341#ifdef CONFIG_SND_HDA_POWER_SAVE
19342 if (!spec->loopback.amplist)
19343 spec->loopback.amplist = alc662_loopbacks;
19344#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019345
19346 return 0;
19347}
19348
Kailang Yang274693f2009-12-03 10:07:50 +010019349static int patch_alc888(struct hda_codec *codec)
19350{
19351 if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){
19352 kfree(codec->chip_name);
19353 codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010019354 if (!codec->chip_name) {
19355 alc_free(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010019356 return -ENOMEM;
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010019357 }
19358 return patch_alc662(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010019359 }
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010019360 return patch_alc882(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010019361}
19362
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019363/*
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019364 * ALC680 support
19365 */
Kailang Yangc69aefa2010-08-17 10:39:22 +020019366#define ALC680_DIGIN_NID ALC880_DIGIN_NID
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019367#define ALC680_DIGOUT_NID ALC880_DIGOUT_NID
19368#define alc680_modes alc260_modes
19369
19370static hda_nid_t alc680_dac_nids[3] = {
19371 /* Lout1, Lout2, hp */
19372 0x02, 0x03, 0x04
19373};
19374
19375static hda_nid_t alc680_adc_nids[3] = {
19376 /* ADC0-2 */
19377 /* DMIC, MIC, Line-in*/
19378 0x07, 0x08, 0x09
19379};
19380
Kailang Yangc69aefa2010-08-17 10:39:22 +020019381/*
19382 * Analog capture ADC cgange
19383 */
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019384static void alc680_rec_autoswitch(struct hda_codec *codec)
19385{
19386 struct alc_spec *spec = codec->spec;
19387 struct auto_pin_cfg *cfg = &spec->autocfg;
19388 int pin_found = 0;
19389 int type_found = AUTO_PIN_LAST;
19390 hda_nid_t nid;
19391 int i;
19392
19393 for (i = 0; i < cfg->num_inputs; i++) {
19394 nid = cfg->inputs[i].pin;
19395 if (!(snd_hda_query_pin_caps(codec, nid) &
19396 AC_PINCAP_PRES_DETECT))
19397 continue;
19398 if (snd_hda_jack_detect(codec, nid)) {
19399 if (cfg->inputs[i].type < type_found) {
19400 type_found = cfg->inputs[i].type;
19401 pin_found = nid;
19402 }
19403 }
19404 }
19405
19406 nid = 0x07;
19407 if (pin_found)
19408 snd_hda_get_connections(codec, pin_found, &nid, 1);
19409
19410 if (nid != spec->cur_adc)
19411 __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
19412 spec->cur_adc = nid;
19413 snd_hda_codec_setup_stream(codec, nid, spec->cur_adc_stream_tag, 0,
19414 spec->cur_adc_format);
19415}
19416
Kailang Yangc69aefa2010-08-17 10:39:22 +020019417static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
19418 struct hda_codec *codec,
19419 unsigned int stream_tag,
19420 unsigned int format,
19421 struct snd_pcm_substream *substream)
19422{
19423 struct alc_spec *spec = codec->spec;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019424
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019425 spec->cur_adc = 0x07;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019426 spec->cur_adc_stream_tag = stream_tag;
19427 spec->cur_adc_format = format;
19428
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019429 alc680_rec_autoswitch(codec);
Kailang Yangc69aefa2010-08-17 10:39:22 +020019430 return 0;
19431}
19432
19433static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
19434 struct hda_codec *codec,
19435 struct snd_pcm_substream *substream)
19436{
19437 snd_hda_codec_cleanup_stream(codec, 0x07);
19438 snd_hda_codec_cleanup_stream(codec, 0x08);
19439 snd_hda_codec_cleanup_stream(codec, 0x09);
19440 return 0;
19441}
19442
19443static struct hda_pcm_stream alc680_pcm_analog_auto_capture = {
19444 .substreams = 1, /* can be overridden */
19445 .channels_min = 2,
19446 .channels_max = 2,
19447 /* NID is set in alc_build_pcms */
19448 .ops = {
19449 .prepare = alc680_capture_pcm_prepare,
19450 .cleanup = alc680_capture_pcm_cleanup
19451 },
19452};
19453
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019454static struct snd_kcontrol_new alc680_base_mixer[] = {
19455 /* output mixer control */
19456 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
19457 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
19458 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT),
19459 HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yangc69aefa2010-08-17 10:39:22 +020019460 HDA_CODEC_VOLUME("Int Mic Boost", 0x12, 0, HDA_INPUT),
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019461 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangc69aefa2010-08-17 10:39:22 +020019462 HDA_CODEC_VOLUME("Line In Boost", 0x19, 0, HDA_INPUT),
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019463 { }
19464};
19465
Kailang Yangc69aefa2010-08-17 10:39:22 +020019466static struct hda_bind_ctls alc680_bind_cap_vol = {
19467 .ops = &snd_hda_bind_vol,
19468 .values = {
19469 HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
19470 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
19471 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
19472 0
19473 },
19474};
19475
19476static struct hda_bind_ctls alc680_bind_cap_switch = {
19477 .ops = &snd_hda_bind_sw,
19478 .values = {
19479 HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
19480 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
19481 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
19482 0
19483 },
19484};
19485
19486static struct snd_kcontrol_new alc680_master_capture_mixer[] = {
19487 HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol),
19488 HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch),
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019489 { } /* end */
19490};
19491
19492/*
19493 * generic initialization of ADC, input mixers and output mixers
19494 */
19495static struct hda_verb alc680_init_verbs[] = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019496 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
19497 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
19498 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019499
Kailang Yangc69aefa2010-08-17 10:39:22 +020019500 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
19501 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
19502 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
19503 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
19504 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
19505 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019506
19507 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19508 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19509 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19510 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19511 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yangc69aefa2010-08-17 10:39:22 +020019512
19513 {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
19514 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019515 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Kailang Yangc69aefa2010-08-17 10:39:22 +020019516
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019517 { }
19518};
19519
Kailang Yangc69aefa2010-08-17 10:39:22 +020019520/* toggle speaker-output according to the hp-jack state */
19521static void alc680_base_setup(struct hda_codec *codec)
19522{
19523 struct alc_spec *spec = codec->spec;
19524
19525 spec->autocfg.hp_pins[0] = 0x16;
19526 spec->autocfg.speaker_pins[0] = 0x14;
19527 spec->autocfg.speaker_pins[1] = 0x15;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019528 spec->autocfg.num_inputs = 2;
19529 spec->autocfg.inputs[0].pin = 0x18;
19530 spec->autocfg.inputs[0].type = AUTO_PIN_MIC;
19531 spec->autocfg.inputs[1].pin = 0x19;
Takashi Iwai86e29592010-09-09 14:50:17 +020019532 spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019533}
19534
19535static void alc680_unsol_event(struct hda_codec *codec,
19536 unsigned int res)
19537{
19538 if ((res >> 26) == ALC880_HP_EVENT)
19539 alc_automute_amp(codec);
19540 if ((res >> 26) == ALC880_MIC_EVENT)
19541 alc680_rec_autoswitch(codec);
19542}
19543
19544static void alc680_inithook(struct hda_codec *codec)
19545{
19546 alc_automute_amp(codec);
19547 alc680_rec_autoswitch(codec);
19548}
19549
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019550/* create input playback/capture controls for the given pin */
19551static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
19552 const char *ctlname, int idx)
19553{
19554 hda_nid_t dac;
19555 int err;
19556
19557 switch (nid) {
19558 case 0x14:
19559 dac = 0x02;
19560 break;
19561 case 0x15:
19562 dac = 0x03;
19563 break;
19564 case 0x16:
19565 dac = 0x04;
19566 break;
19567 default:
19568 return 0;
19569 }
19570 if (spec->multiout.dac_nids[0] != dac &&
19571 spec->multiout.dac_nids[1] != dac) {
19572 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
19573 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
19574 HDA_OUTPUT));
19575 if (err < 0)
19576 return err;
19577
19578 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
19579 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
19580
19581 if (err < 0)
19582 return err;
19583 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
19584 }
19585
19586 return 0;
19587}
19588
19589/* add playback controls from the parsed DAC table */
19590static int alc680_auto_create_multi_out_ctls(struct alc_spec *spec,
19591 const struct auto_pin_cfg *cfg)
19592{
19593 hda_nid_t nid;
19594 int err;
19595
19596 spec->multiout.dac_nids = spec->private_dac_nids;
19597
19598 nid = cfg->line_out_pins[0];
19599 if (nid) {
19600 const char *name;
19601 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
19602 name = "Speaker";
19603 else
19604 name = "Front";
19605 err = alc680_new_analog_output(spec, nid, name, 0);
19606 if (err < 0)
19607 return err;
19608 }
19609
19610 nid = cfg->speaker_pins[0];
19611 if (nid) {
19612 err = alc680_new_analog_output(spec, nid, "Speaker", 0);
19613 if (err < 0)
19614 return err;
19615 }
19616 nid = cfg->hp_pins[0];
19617 if (nid) {
19618 err = alc680_new_analog_output(spec, nid, "Headphone", 0);
19619 if (err < 0)
19620 return err;
19621 }
19622
19623 return 0;
19624}
19625
19626static void alc680_auto_set_output_and_unmute(struct hda_codec *codec,
19627 hda_nid_t nid, int pin_type)
19628{
19629 alc_set_pin_output(codec, nid, pin_type);
19630}
19631
19632static void alc680_auto_init_multi_out(struct hda_codec *codec)
19633{
19634 struct alc_spec *spec = codec->spec;
19635 hda_nid_t nid = spec->autocfg.line_out_pins[0];
19636 if (nid) {
19637 int pin_type = get_pin_type(spec->autocfg.line_out_type);
19638 alc680_auto_set_output_and_unmute(codec, nid, pin_type);
19639 }
19640}
19641
19642static void alc680_auto_init_hp_out(struct hda_codec *codec)
19643{
19644 struct alc_spec *spec = codec->spec;
19645 hda_nid_t pin;
19646
19647 pin = spec->autocfg.hp_pins[0];
19648 if (pin)
19649 alc680_auto_set_output_and_unmute(codec, pin, PIN_HP);
19650 pin = spec->autocfg.speaker_pins[0];
19651 if (pin)
19652 alc680_auto_set_output_and_unmute(codec, pin, PIN_OUT);
19653}
19654
19655/* pcm configuration: identical with ALC880 */
19656#define alc680_pcm_analog_playback alc880_pcm_analog_playback
19657#define alc680_pcm_analog_capture alc880_pcm_analog_capture
19658#define alc680_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
19659#define alc680_pcm_digital_playback alc880_pcm_digital_playback
Kailang Yangc69aefa2010-08-17 10:39:22 +020019660#define alc680_pcm_digital_capture alc880_pcm_digital_capture
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019661
19662/*
19663 * BIOS auto configuration
19664 */
19665static int alc680_parse_auto_config(struct hda_codec *codec)
19666{
19667 struct alc_spec *spec = codec->spec;
19668 int err;
19669 static hda_nid_t alc680_ignore[] = { 0 };
19670
19671 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
19672 alc680_ignore);
19673 if (err < 0)
19674 return err;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019675
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019676 if (!spec->autocfg.line_outs) {
19677 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
19678 spec->multiout.max_channels = 2;
19679 spec->no_analog = 1;
19680 goto dig_only;
19681 }
19682 return 0; /* can't find valid BIOS pin config */
19683 }
19684 err = alc680_auto_create_multi_out_ctls(spec, &spec->autocfg);
19685 if (err < 0)
19686 return err;
19687
19688 spec->multiout.max_channels = 2;
19689
19690 dig_only:
19691 /* digital only support output */
Takashi Iwai757899a2010-07-30 10:48:14 +020019692 alc_auto_parse_digital(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019693 if (spec->kctls.list)
19694 add_mixer(spec, spec->kctls.list);
19695
19696 add_verb(spec, alc680_init_verbs);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019697
19698 err = alc_auto_add_mic_boost(codec);
19699 if (err < 0)
19700 return err;
19701
19702 return 1;
19703}
19704
19705#define alc680_auto_init_analog_input alc882_auto_init_analog_input
19706
19707/* init callback for auto-configuration model -- overriding the default init */
19708static void alc680_auto_init(struct hda_codec *codec)
19709{
19710 struct alc_spec *spec = codec->spec;
19711 alc680_auto_init_multi_out(codec);
19712 alc680_auto_init_hp_out(codec);
19713 alc680_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020019714 alc_auto_init_digital(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019715 if (spec->unsol_event)
19716 alc_inithook(codec);
19717}
19718
19719/*
19720 * configuration and preset
19721 */
19722static const char *alc680_models[ALC680_MODEL_LAST] = {
Takashi Iwaid4a86d82010-06-23 17:51:26 +020019723 [ALC680_BASE] = "base",
19724 [ALC680_AUTO] = "auto",
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019725};
19726
19727static struct snd_pci_quirk alc680_cfg_tbl[] = {
19728 SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE),
19729 {}
19730};
19731
19732static struct alc_config_preset alc680_presets[] = {
19733 [ALC680_BASE] = {
19734 .mixers = { alc680_base_mixer },
Kailang Yangc69aefa2010-08-17 10:39:22 +020019735 .cap_mixer = alc680_master_capture_mixer,
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019736 .init_verbs = { alc680_init_verbs },
19737 .num_dacs = ARRAY_SIZE(alc680_dac_nids),
19738 .dac_nids = alc680_dac_nids,
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019739 .dig_out_nid = ALC680_DIGOUT_NID,
19740 .num_channel_mode = ARRAY_SIZE(alc680_modes),
19741 .channel_mode = alc680_modes,
Kailang Yangc69aefa2010-08-17 10:39:22 +020019742 .unsol_event = alc680_unsol_event,
19743 .setup = alc680_base_setup,
19744 .init_hook = alc680_inithook,
19745
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019746 },
19747};
19748
19749static int patch_alc680(struct hda_codec *codec)
19750{
19751 struct alc_spec *spec;
19752 int board_config;
19753 int err;
19754
19755 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
19756 if (spec == NULL)
19757 return -ENOMEM;
19758
19759 codec->spec = spec;
19760
19761 board_config = snd_hda_check_board_config(codec, ALC680_MODEL_LAST,
19762 alc680_models,
19763 alc680_cfg_tbl);
19764
19765 if (board_config < 0 || board_config >= ALC680_MODEL_LAST) {
19766 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
19767 codec->chip_name);
19768 board_config = ALC680_AUTO;
19769 }
19770
19771 if (board_config == ALC680_AUTO) {
19772 /* automatic parse from the BIOS config */
19773 err = alc680_parse_auto_config(codec);
19774 if (err < 0) {
19775 alc_free(codec);
19776 return err;
19777 } else if (!err) {
19778 printk(KERN_INFO
19779 "hda_codec: Cannot set up configuration "
19780 "from BIOS. Using base mode...\n");
19781 board_config = ALC680_BASE;
19782 }
19783 }
19784
19785 if (board_config != ALC680_AUTO)
19786 setup_preset(codec, &alc680_presets[board_config]);
19787
19788 spec->stream_analog_playback = &alc680_pcm_analog_playback;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019789 spec->stream_analog_capture = &alc680_pcm_analog_auto_capture;
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019790 spec->stream_digital_playback = &alc680_pcm_digital_playback;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019791 spec->stream_digital_capture = &alc680_pcm_digital_capture;
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019792
19793 if (!spec->adc_nids) {
19794 spec->adc_nids = alc680_adc_nids;
19795 spec->num_adc_nids = ARRAY_SIZE(alc680_adc_nids);
19796 }
19797
19798 if (!spec->cap_mixer)
19799 set_capture_mixer(codec);
19800
19801 spec->vmaster_nid = 0x02;
19802
19803 codec->patch_ops = alc_patch_ops;
19804 if (board_config == ALC680_AUTO)
19805 spec->init_hook = alc680_auto_init;
19806
19807 return 0;
19808}
19809
19810/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070019811 * patch entries
19812 */
Takashi Iwai1289e9e2008-11-27 15:47:11 +010019813static struct hda_codec_preset snd_hda_preset_realtek[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070019814 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010019815 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010019816 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020019817 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010019818 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010019819 { .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +020019820 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010019821 { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019822 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019823 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019824 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
19825 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
19826 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019827 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
Takashi Iwai4953550a2009-06-30 15:28:30 +020019828 .patch = patch_alc882 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019829 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
19830 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020019831 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Kailang Yangcec27c82010-02-04 14:18:18 +010019832 { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
Kailang Yang6227cdc2010-02-25 08:36:52 +010019833 { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019834 { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019835 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070019836 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020019837 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
Clive Messer669faba2008-09-30 15:49:13 +020019838 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
Takashi Iwai4953550a2009-06-30 15:28:30 +020019839 .patch = patch_alc882 },
Takashi Iwaicb308f92008-04-16 14:13:29 +020019840 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai4953550a2009-06-30 15:28:30 +020019841 .patch = patch_alc882 },
Kailang Yangdf694da2005-12-05 19:42:22 +010019842 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020019843 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 },
Kailang Yang44426082008-10-15 11:18:05 +020019844 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
Takashi Iwai4953550a2009-06-30 15:28:30 +020019845 .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010019846 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020019847 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010019848 { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070019849 {} /* terminator */
19850};
Takashi Iwai1289e9e2008-11-27 15:47:11 +010019851
19852MODULE_ALIAS("snd-hda-codec-id:10ec*");
19853
19854MODULE_LICENSE("GPL");
19855MODULE_DESCRIPTION("Realtek HD-audio codec");
19856
19857static struct hda_codec_preset_list realtek_list = {
19858 .preset = snd_hda_preset_realtek,
19859 .owner = THIS_MODULE,
19860};
19861
19862static int __init patch_realtek_init(void)
19863{
19864 return snd_hda_add_codec_preset(&realtek_list);
19865}
19866
19867static void __exit patch_realtek_exit(void)
19868{
19869 snd_hda_delete_codec_preset(&realtek_list);
19870}
19871
19872module_init(patch_realtek_init)
19873module_exit(patch_realtek_exit)