blob: c41ac30ffc7f11841b6c28478c8ba1d6af3e0689 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for ALC 260/880/882 codecs
5 *
Kailang Yangdf694da2005-12-05 19:42:22 +01006 * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
7 * PeiSen Hou <pshou@realtek.com.tw>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * Takashi Iwai <tiwai@suse.de>
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01009 * Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * This driver is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This driver is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/init.h>
27#include <linux/delay.h>
28#include <linux/slab.h>
29#include <linux/pci.h>
30#include <sound/core.h>
Kailang Yang9ad0e492010-09-14 23:22:00 +020031#include <sound/jack.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include "hda_codec.h"
33#include "hda_local.h"
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090034#include "hda_beep.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
Kailang Yangccc656c2006-10-17 12:32:26 +020036#define ALC880_FRONT_EVENT 0x01
37#define ALC880_DCVOL_EVENT 0x02
38#define ALC880_HP_EVENT 0x04
39#define ALC880_MIC_EVENT 0x08
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
41/* ALC880 board config type */
42enum {
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 ALC880_3ST,
44 ALC880_3ST_DIG,
45 ALC880_5ST,
46 ALC880_5ST_DIG,
47 ALC880_W810,
Takashi Iwaidfc0ff62005-05-12 14:31:49 +020048 ALC880_Z71V,
Takashi Iwaib6482d42005-06-27 15:32:43 +020049 ALC880_6ST,
Takashi Iwai16ded522005-06-10 19:58:24 +020050 ALC880_6ST_DIG,
51 ALC880_F1734,
52 ALC880_ASUS,
53 ALC880_ASUS_DIG,
54 ALC880_ASUS_W1V,
Kailang Yangdf694da2005-12-05 19:42:22 +010055 ALC880_ASUS_DIG2,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +010056 ALC880_FUJITSU,
Takashi Iwai16ded522005-06-10 19:58:24 +020057 ALC880_UNIWILL_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +020058 ALC880_UNIWILL,
59 ALC880_UNIWILL_P53,
Kailang Yangdf694da2005-12-05 19:42:22 +010060 ALC880_CLEVO,
61 ALC880_TCL_S700,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010062 ALC880_LG,
Takashi Iwaid6815182006-03-23 16:06:23 +010063 ALC880_LG_LW,
Takashi Iwaidf99cd32008-04-25 15:25:04 +020064 ALC880_MEDION_RIM,
Takashi Iwaie9edcee2005-06-13 14:16:38 +020065#ifdef CONFIG_SND_DEBUG
66 ALC880_TEST,
67#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010068 ALC880_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020069 ALC880_MODEL_LAST /* last tag */
70};
71
72/* ALC260 models */
73enum {
74 ALC260_BASIC,
75 ALC260_HP,
Kailang Yang3f878302008-08-26 13:02:23 +020076 ALC260_HP_DC7600,
Kailang Yangdf694da2005-12-05 19:42:22 +010077 ALC260_HP_3013,
78 ALC260_FUJITSU_S702X,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +010079 ALC260_ACER,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020080 ALC260_WILL,
81 ALC260_REPLACER_672V,
Michael Schwingencc959482009-02-22 18:58:45 +010082 ALC260_FAVORIT100,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +010083#ifdef CONFIG_SND_DEBUG
84 ALC260_TEST,
85#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010086 ALC260_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020087 ALC260_MODEL_LAST /* last tag */
Linus Torvalds1da177e2005-04-16 15:20:36 -070088};
89
Kailang Yangdf694da2005-12-05 19:42:22 +010090/* ALC262 models */
91enum {
92 ALC262_BASIC,
Kailang Yangccc656c2006-10-17 12:32:26 +020093 ALC262_HIPPO,
94 ALC262_HIPPO_1,
Takashi Iwai834be882006-03-01 14:16:17 +010095 ALC262_FUJITSU,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020096 ALC262_HP_BPC,
Kailang Yangcd7509a2007-01-26 18:33:17 +010097 ALC262_HP_BPC_D7000_WL,
98 ALC262_HP_BPC_D7000_WF,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010099 ALC262_HP_TC_T5735,
Kailang Yang8c427222008-01-10 13:03:59 +0100100 ALC262_HP_RP5700,
Takashi Iwai304dcaa2006-07-25 14:51:16 +0200101 ALC262_BENQ_ED8,
Kailang Yang272a5272007-05-14 11:00:38 +0200102 ALC262_SONY_ASSAMD,
Kailang Yang83c34212007-07-05 11:43:05 +0200103 ALC262_BENQ_T31,
Tobin Davisf651b502007-10-26 12:40:47 +0200104 ALC262_ULTRA,
Jiang zhe0e31daf2008-03-20 12:12:39 +0100105 ALC262_LENOVO_3000,
Pascal Terjane8f9ae22008-08-04 14:36:05 +0200106 ALC262_NEC,
Kailang Yang4e555fe2008-08-26 13:05:55 +0200107 ALC262_TOSHIBA_S06,
Hiroshi Miura9f99a632008-08-28 16:09:06 +0200108 ALC262_TOSHIBA_RX1,
Tony Vroonba340e82009-02-02 19:01:30 +0000109 ALC262_TYAN,
Kailang Yangdf694da2005-12-05 19:42:22 +0100110 ALC262_AUTO,
111 ALC262_MODEL_LAST /* last tag */
112};
113
Kailang Yanga361d842007-06-05 12:30:55 +0200114/* ALC268 models */
115enum {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +0200116 ALC267_QUANTA_IL1,
Kailang Yanga361d842007-06-05 12:30:55 +0200117 ALC268_3ST,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200118 ALC268_TOSHIBA,
Takashi Iwaid2738092007-08-16 14:59:45 +0200119 ALC268_ACER,
Takashi Iwaic238b4f2008-11-05 14:57:20 +0100120 ALC268_ACER_DMIC,
Kailang Yang8ef355d2008-08-26 13:10:22 +0200121 ALC268_ACER_ASPIRE_ONE,
Takashi Iwai3866f0b2008-01-15 12:37:42 +0100122 ALC268_DELL,
Mirco Tischlerf12462c2008-02-04 12:33:59 +0100123 ALC268_ZEPTO,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +0100124#ifdef CONFIG_SND_DEBUG
125 ALC268_TEST,
126#endif
Kailang Yanga361d842007-06-05 12:30:55 +0200127 ALC268_AUTO,
128 ALC268_MODEL_LAST /* last tag */
129};
130
Kailang Yangf6a92242007-12-13 16:52:54 +0100131/* ALC269 models */
132enum {
133 ALC269_BASIC,
Kailang Yang60db6b52008-08-26 13:13:00 +0200134 ALC269_QUANTA_FL1,
Kailang Yang84898e82010-02-04 14:16:14 +0100135 ALC269_AMIC,
136 ALC269_DMIC,
137 ALC269VB_AMIC,
138 ALC269VB_DMIC,
Takashi Iwai26f5df22008-11-03 17:39:46 +0100139 ALC269_FUJITSU,
Tony Vroon64154832008-11-06 15:08:49 +0000140 ALC269_LIFEBOOK,
Kailang Yangfe3eb0a2010-08-06 10:02:57 +0200141 ALC271_ACER,
Kailang Yangf6a92242007-12-13 16:52:54 +0100142 ALC269_AUTO,
143 ALC269_MODEL_LAST /* last tag */
144};
145
Kailang Yangdf694da2005-12-05 19:42:22 +0100146/* ALC861 models */
147enum {
148 ALC861_3ST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200149 ALC660_3ST,
Kailang Yangdf694da2005-12-05 19:42:22 +0100150 ALC861_3ST_DIG,
151 ALC861_6ST_DIG,
Takashi Iwai22309c32006-08-09 16:57:28 +0200152 ALC861_UNIWILL_M31,
Tobin Davisa53d1ae2006-10-17 12:00:28 +0200153 ALC861_TOSHIBA,
Mariusz Domanski7cdbff92006-10-23 13:42:56 +0200154 ALC861_ASUS,
Takashi Iwai56bb0ca2006-11-22 11:52:52 +0100155 ALC861_ASUS_LAPTOP,
Kailang Yangdf694da2005-12-05 19:42:22 +0100156 ALC861_AUTO,
157 ALC861_MODEL_LAST,
158};
159
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100160/* ALC861-VD models */
161enum {
162 ALC660VD_3ST,
Mike Crash6963f842007-06-25 12:12:51 +0200163 ALC660VD_3ST_DIG,
Takashi Iwai13c94742008-11-05 08:06:08 +0100164 ALC660VD_ASUS_V1S,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100165 ALC861VD_3ST,
166 ALC861VD_3ST_DIG,
167 ALC861VD_6ST_DIG,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200168 ALC861VD_LENOVO,
Kailang Yang272a5272007-05-14 11:00:38 +0200169 ALC861VD_DALLAS,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200170 ALC861VD_HP,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100171 ALC861VD_AUTO,
172 ALC861VD_MODEL_LAST,
173};
174
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200175/* ALC662 models */
176enum {
177 ALC662_3ST_2ch_DIG,
178 ALC662_3ST_6ch_DIG,
179 ALC662_3ST_6ch,
180 ALC662_5ST_DIG,
181 ALC662_LENOVO_101E,
Kailang Yang291702f2007-10-16 14:28:03 +0200182 ALC662_ASUS_EEEPC_P701,
Kailang Yang8c427222008-01-10 13:03:59 +0100183 ALC662_ASUS_EEEPC_EP20,
Kailang Yang6dda9f42008-05-27 12:05:31 +0200184 ALC663_ASUS_M51VA,
185 ALC663_ASUS_G71V,
186 ALC663_ASUS_H13,
187 ALC663_ASUS_G50V,
Kailang Yangf1d4e282008-08-26 14:03:29 +0200188 ALC662_ECS,
189 ALC663_ASUS_MODE1,
190 ALC662_ASUS_MODE2,
191 ALC663_ASUS_MODE3,
192 ALC663_ASUS_MODE4,
193 ALC663_ASUS_MODE5,
194 ALC663_ASUS_MODE6,
Kailang Yangebb83ee2009-12-17 12:23:00 +0100195 ALC663_ASUS_MODE7,
196 ALC663_ASUS_MODE8,
Kailang Yang622e84c2009-04-21 07:39:04 +0200197 ALC272_DELL,
198 ALC272_DELL_ZM1,
Chris Pockelé9541ba12009-05-12 08:08:53 +0200199 ALC272_SAMSUNG_NC10,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200200 ALC662_AUTO,
201 ALC662_MODEL_LAST,
202};
203
Kailang Yangdf694da2005-12-05 19:42:22 +0100204/* ALC882 models */
205enum {
206 ALC882_3ST_DIG,
207 ALC882_6ST_DIG,
Takashi Iwai4b146cb2006-07-28 14:42:36 +0200208 ALC882_ARIMA,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200209 ALC882_W2JC,
Kailang Yang272a5272007-05-14 11:00:38 +0200210 ALC882_TARGA,
211 ALC882_ASUS_A7J,
Takashi Iwai914759b2007-09-06 14:52:04 +0200212 ALC882_ASUS_A7M,
Tobin Davis9102cd12006-12-15 10:02:12 +0100213 ALC885_MACPRO,
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -0800214 ALC885_MBA21,
Takashi Iwai87350ad2007-08-16 18:19:38 +0200215 ALC885_MBP3,
Kacper Szczesniak41d55452009-05-07 12:47:43 +0200216 ALC885_MB5,
Luke Yelaviche458b1f2010-02-12 16:28:29 +1100217 ALC885_MACMINI3,
Nicola Fagnanic54728d2007-07-19 23:28:52 +0200218 ALC885_IMAC24,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -0800219 ALC885_IMAC91,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200220 ALC883_3ST_2ch_DIG,
221 ALC883_3ST_6ch_DIG,
222 ALC883_3ST_6ch,
223 ALC883_6ST_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +0200224 ALC883_TARGA_DIG,
225 ALC883_TARGA_2ch_DIG,
David Heidelberger64a8be72009-06-08 16:15:18 +0200226 ALC883_TARGA_8ch_DIG,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +0200227 ALC883_ACER,
Tobin Davis2880a862007-08-07 11:50:26 +0200228 ALC883_ACER_ASPIRE,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +0800229 ALC888_ACER_ASPIRE_4930G,
Tony Vroond2fd4b02009-06-21 00:40:10 +0100230 ALC888_ACER_ASPIRE_6530G,
Hector Martin3b315d72009-06-02 10:54:19 +0200231 ALC888_ACER_ASPIRE_8930G,
Denis Kuplyakovfc86f952009-08-25 18:15:59 +0200232 ALC888_ACER_ASPIRE_7730G,
Tobin Davisc07584c2006-10-13 12:32:16 +0200233 ALC883_MEDION,
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ünther3e1647c2009-06-05 00:47:26 +0200256 ALC883_SONY_VAIO_TT,
Takashi Iwai49535502009-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 Iwai49535502009-06-30 15:28:30 +0200376 hda_nid_t private_adc_nids[AUTO_CFG_MAX_OUTS];
377 hda_nid_t private_capsrc_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai834be882006-03-01 14:16:17 +0100378
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100379 /* hooks */
380 void (*init_hook)(struct hda_codec *codec);
381 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
Hector Martinf5de24b2009-12-20 22:51:31 +0100382#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -0500383 void (*power_hook)(struct hda_codec *codec);
Hector Martinf5de24b2009-12-20 22:51:31 +0100384#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100385
Takashi Iwai834be882006-03-01 14:16:17 +0100386 /* for pin sensing */
387 unsigned int sense_updated: 1;
388 unsigned int jack_present: 1;
Takashi Iwaibec15c32008-01-28 18:16:30 +0100389 unsigned int master_sw: 1;
Takashi Iwai6c819492009-08-10 18:47:44 +0200390 unsigned int auto_mic:1;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200391
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100392 /* other flags */
393 unsigned int no_analog :1; /* digital I/O only */
Takashi Iwai840b64c2010-07-13 22:49:01 +0200394 unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200395 int init_amp;
Takashi Iwaid433a672010-09-20 15:11:54 +0200396 int codec_variant; /* flag for other variants */
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100397
Takashi Iwai2134ea42008-01-10 16:53:55 +0100398 /* for virtual master */
399 hda_nid_t vmaster_nid;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200400#ifdef CONFIG_SND_HDA_POWER_SAVE
401 struct hda_loopback_check loopback;
402#endif
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200403
404 /* for PLL fix */
405 hda_nid_t pll_nid;
406 unsigned int pll_coef_idx, pll_coef_bit;
Kailang Yangdf694da2005-12-05 19:42:22 +0100407};
408
409/*
410 * configuration template - to be copied to the spec instance
411 */
412struct alc_config_preset {
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200413 struct snd_kcontrol_new *mixers[5]; /* should be identical size
414 * with spec
415 */
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100416 struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Kailang Yangdf694da2005-12-05 19:42:22 +0100417 const struct hda_verb *init_verbs[5];
418 unsigned int num_dacs;
419 hda_nid_t *dac_nids;
420 hda_nid_t dig_out_nid; /* optional */
421 hda_nid_t hp_nid; /* optional */
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800422 hda_nid_t *slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100423 unsigned int num_adc_nids;
424 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100425 hda_nid_t *capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100426 hda_nid_t dig_in_nid;
427 unsigned int num_channel_mode;
428 const struct hda_channel_mode *channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200429 int need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200430 int const_channel_count;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200431 unsigned int num_mux_defs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100432 const struct hda_input_mux *input_mux;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100433 void (*unsol_event)(struct hda_codec *, unsigned int);
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200434 void (*setup)(struct hda_codec *);
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100435 void (*init_hook)(struct hda_codec *);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200436#ifdef CONFIG_SND_HDA_POWER_SAVE
437 struct hda_amp_list *loopbacks;
Daniel T Chenc97259d2009-12-27 18:52:08 -0500438 void (*power_hook)(struct hda_codec *codec);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200439#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440};
441
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442
443/*
444 * input MUX handling
445 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200446static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
447 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448{
449 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
450 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200451 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
452 if (mux_idx >= spec->num_mux_defs)
453 mux_idx = 0;
Takashi Iwai53111142010-03-08 12:13:07 +0100454 if (!spec->input_mux[mux_idx].num_items && mux_idx > 0)
455 mux_idx = 0;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200456 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457}
458
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200459static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
460 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461{
462 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
463 struct alc_spec *spec = codec->spec;
464 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
465
466 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
467 return 0;
468}
469
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200470static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
471 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472{
473 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
474 struct alc_spec *spec = codec->spec;
Takashi Iwaicd896c32008-11-18 12:36:33 +0100475 const struct hda_input_mux *imux;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwaicd896c32008-11-18 12:36:33 +0100477 unsigned int mux_idx;
Takashi Iwaie1406342008-02-11 18:32:32 +0100478 hda_nid_t nid = spec->capsrc_nids ?
479 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Takashi Iwai0169b6b2009-06-22 10:50:19 +0200480 unsigned int type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481
Takashi Iwaicd896c32008-11-18 12:36:33 +0100482 mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
483 imux = &spec->input_mux[mux_idx];
Takashi Iwai53111142010-03-08 12:13:07 +0100484 if (!imux->num_items && mux_idx > 0)
485 imux = &spec->input_mux[0];
Takashi Iwaicd896c32008-11-18 12:36:33 +0100486
Takashi Iwaia22d5432009-07-27 12:54:26 +0200487 type = get_wcaps_type(get_wcaps(codec, nid));
Takashi Iwai0169b6b2009-06-22 10:50:19 +0200488 if (type == AC_WID_AUD_MIX) {
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100489 /* Matrix-mixer style (e.g. ALC882) */
490 unsigned int *cur_val = &spec->cur_mux[adc_idx];
491 unsigned int i, idx;
492
493 idx = ucontrol->value.enumerated.item[0];
494 if (idx >= imux->num_items)
495 idx = imux->num_items - 1;
496 if (*cur_val == idx)
497 return 0;
498 for (i = 0; i < imux->num_items; i++) {
499 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
500 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
501 imux->items[i].index,
502 HDA_AMP_MUTE, v);
503 }
504 *cur_val = idx;
505 return 1;
506 } else {
507 /* MUX style (e.g. ALC880) */
Takashi Iwaicd896c32008-11-18 12:36:33 +0100508 return snd_hda_input_mux_put(codec, imux, ucontrol, nid,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100509 &spec->cur_mux[adc_idx]);
510 }
511}
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200512
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513/*
514 * channel mode setting
515 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200516static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
517 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518{
519 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
520 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100521 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
522 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523}
524
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200525static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
526 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527{
528 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
529 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100530 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200531 spec->num_channel_mode,
Hector Martin3b315d72009-06-02 10:54:19 +0200532 spec->ext_channel_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533}
534
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200535static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
536 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537{
538 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
539 struct alc_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200540 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
541 spec->num_channel_mode,
Hector Martin3b315d72009-06-02 10:54:19 +0200542 &spec->ext_channel_count);
543 if (err >= 0 && !spec->const_channel_count) {
544 spec->multiout.max_channels = spec->ext_channel_count;
545 if (spec->need_dac_fix)
546 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
547 }
Takashi Iwai4e195a72006-07-28 14:47:34 +0200548 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549}
550
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100552 * Control the mode of pin widget settings via the mixer. "pc" is used
Kailang Yangea1fb292008-08-26 12:58:38 +0200553 * instead of "%" to avoid consequences of accidently treating the % as
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100554 * being part of a format specifier. Maximum allowed length of a value is
555 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100556 *
557 * Note: some retasking pin complexes seem to ignore requests for input
558 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
559 * are requested. Therefore order this list so that this behaviour will not
560 * cause problems when mixer clients move through the enum sequentially.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200561 * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
562 * March 2006.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200563 */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100564static char *alc_pin_mode_names[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100565 "Mic 50pc bias", "Mic 80pc bias",
566 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100567};
568static unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100569 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100570};
571/* The control can present all 5 options, or it can limit the options based
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200572 * in the pin being assumed to be exclusively an input or an output pin. In
573 * addition, "input" pins may or may not process the mic bias option
574 * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
575 * accept requests for bias as of chip versions up to March 2006) and/or
576 * wiring in the computer.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100577 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200578#define ALC_PIN_DIR_IN 0x00
579#define ALC_PIN_DIR_OUT 0x01
580#define ALC_PIN_DIR_INOUT 0x02
581#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
582#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100583
Kailang Yangea1fb292008-08-26 12:58:38 +0200584/* Info about the pin modes supported by the different pin direction modes.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100585 * For each direction the minimum and maximum values are given.
586 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200587static signed char alc_pin_mode_dir_info[5][2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100588 { 0, 2 }, /* ALC_PIN_DIR_IN */
589 { 3, 4 }, /* ALC_PIN_DIR_OUT */
590 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200591 { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
592 { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100593};
594#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
595#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
596#define alc_pin_mode_n_items(_dir) \
597 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
598
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200599static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
600 struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200601{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100602 unsigned int item_num = uinfo->value.enumerated.item;
603 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
604
605 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200606 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100607 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
608
609 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
610 item_num = alc_pin_mode_min(dir);
611 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200612 return 0;
613}
614
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200615static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
616 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200617{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100618 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200619 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
620 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100621 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200622 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200623 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
624 AC_VERB_GET_PIN_WIDGET_CONTROL,
625 0x00);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200626
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100627 /* Find enumerated value for current pinctl setting */
628 i = alc_pin_mode_min(dir);
Roel Kluin4b35d2c2009-08-02 13:30:45 +0200629 while (i <= alc_pin_mode_max(dir) && alc_pin_mode_values[i] != pinctl)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100630 i++;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200631 *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100632 return 0;
633}
634
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200635static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
636 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100637{
638 signed int change;
639 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
640 hda_nid_t nid = kcontrol->private_value & 0xffff;
641 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
642 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200643 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
644 AC_VERB_GET_PIN_WIDGET_CONTROL,
645 0x00);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100646
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200647 if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100648 val = alc_pin_mode_min(dir);
649
650 change = pinctl != alc_pin_mode_values[val];
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100651 if (change) {
652 /* Set pin mode to that requested */
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200653 snd_hda_codec_write_cache(codec, nid, 0,
654 AC_VERB_SET_PIN_WIDGET_CONTROL,
655 alc_pin_mode_values[val]);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100656
Kailang Yangea1fb292008-08-26 12:58:38 +0200657 /* Also enable the retasking pin's input/output as required
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100658 * for the requested pin mode. Enum values of 2 or less are
659 * input modes.
660 *
661 * Dynamically switching the input/output buffers probably
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200662 * reduces noise slightly (particularly on input) so we'll
663 * do it. However, having both input and output buffers
664 * enabled simultaneously doesn't seem to be problematic if
665 * this turns out to be necessary in the future.
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100666 */
667 if (val <= 2) {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200668 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
669 HDA_AMP_MUTE, HDA_AMP_MUTE);
670 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
671 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100672 } else {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200673 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
674 HDA_AMP_MUTE, HDA_AMP_MUTE);
675 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
676 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100677 }
678 }
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200679 return change;
680}
681
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100682#define ALC_PIN_MODE(xname, nid, dir) \
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200683 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100684 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100685 .info = alc_pin_mode_info, \
686 .get = alc_pin_mode_get, \
687 .put = alc_pin_mode_put, \
688 .private_value = nid | (dir<<16) }
Kailang Yangdf694da2005-12-05 19:42:22 +0100689
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100690/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
691 * together using a mask with more than one bit set. This control is
692 * currently used only by the ALC260 test model. At this stage they are not
693 * needed for any "production" models.
694 */
695#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200696#define alc_gpio_data_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200697
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200698static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
699 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100700{
701 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
702 hda_nid_t nid = kcontrol->private_value & 0xffff;
703 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
704 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200705 unsigned int val = snd_hda_codec_read(codec, nid, 0,
706 AC_VERB_GET_GPIO_DATA, 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100707
708 *valp = (val & mask) != 0;
709 return 0;
710}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200711static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
712 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100713{
714 signed int change;
715 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
716 hda_nid_t nid = kcontrol->private_value & 0xffff;
717 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
718 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200719 unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
720 AC_VERB_GET_GPIO_DATA,
721 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100722
723 /* Set/unset the masked GPIO bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200724 change = (val == 0 ? 0 : mask) != (gpio_data & mask);
725 if (val == 0)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100726 gpio_data &= ~mask;
727 else
728 gpio_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200729 snd_hda_codec_write_cache(codec, nid, 0,
730 AC_VERB_SET_GPIO_DATA, gpio_data);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100731
732 return change;
733}
734#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
735 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100736 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100737 .info = alc_gpio_data_info, \
738 .get = alc_gpio_data_get, \
739 .put = alc_gpio_data_put, \
740 .private_value = nid | (mask<<16) }
741#endif /* CONFIG_SND_DEBUG */
742
Jonathan Woithe92621f12006-02-28 11:47:47 +0100743/* A switch control to allow the enabling of the digital IO pins on the
744 * ALC260. This is incredibly simplistic; the intention of this control is
745 * to provide something in the test model allowing digital outputs to be
746 * identified if present. If models are found which can utilise these
747 * outputs a more complete mixer control can be devised for those models if
748 * necessary.
749 */
750#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200751#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200752
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200753static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
754 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100755{
756 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
757 hda_nid_t nid = kcontrol->private_value & 0xffff;
758 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
759 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200760 unsigned int val = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100761 AC_VERB_GET_DIGI_CONVERT_1, 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100762
763 *valp = (val & mask) != 0;
764 return 0;
765}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200766static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
767 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100768{
769 signed int change;
770 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
771 hda_nid_t nid = kcontrol->private_value & 0xffff;
772 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
773 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200774 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100775 AC_VERB_GET_DIGI_CONVERT_1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200776 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100777
778 /* Set/unset the masked control bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200779 change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100780 if (val==0)
781 ctrl_data &= ~mask;
782 else
783 ctrl_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200784 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
785 ctrl_data);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100786
787 return change;
788}
789#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
790 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100791 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe92621f12006-02-28 11:47:47 +0100792 .info = alc_spdif_ctrl_info, \
793 .get = alc_spdif_ctrl_get, \
794 .put = alc_spdif_ctrl_put, \
795 .private_value = nid | (mask<<16) }
796#endif /* CONFIG_SND_DEBUG */
797
Jonathan Woithef8225f62008-01-08 12:16:54 +0100798/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
799 * Again, this is only used in the ALC26x test models to help identify when
800 * the EAPD line must be asserted for features to work.
801 */
802#ifdef CONFIG_SND_DEBUG
803#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
804
805static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
806 struct snd_ctl_elem_value *ucontrol)
807{
808 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
809 hda_nid_t nid = kcontrol->private_value & 0xffff;
810 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
811 long *valp = ucontrol->value.integer.value;
812 unsigned int val = snd_hda_codec_read(codec, nid, 0,
813 AC_VERB_GET_EAPD_BTLENABLE, 0x00);
814
815 *valp = (val & mask) != 0;
816 return 0;
817}
818
819static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
820 struct snd_ctl_elem_value *ucontrol)
821{
822 int change;
823 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
824 hda_nid_t nid = kcontrol->private_value & 0xffff;
825 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
826 long val = *ucontrol->value.integer.value;
827 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
828 AC_VERB_GET_EAPD_BTLENABLE,
829 0x00);
830
831 /* Set/unset the masked control bit(s) as needed */
832 change = (!val ? 0 : mask) != (ctrl_data & mask);
833 if (!val)
834 ctrl_data &= ~mask;
835 else
836 ctrl_data |= mask;
837 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
838 ctrl_data);
839
840 return change;
841}
842
843#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
844 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100845 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithef8225f62008-01-08 12:16:54 +0100846 .info = alc_eapd_ctrl_info, \
847 .get = alc_eapd_ctrl_get, \
848 .put = alc_eapd_ctrl_put, \
849 .private_value = nid | (mask<<16) }
850#endif /* CONFIG_SND_DEBUG */
851
Kailang Yangdf694da2005-12-05 19:42:22 +0100852/*
Takashi Iwai23f0c042009-02-26 13:03:58 +0100853 * set up the input pin config (depending on the given auto-pin type)
854 */
855static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
856 int auto_pin_type)
857{
858 unsigned int val = PIN_IN;
859
Takashi Iwai86e29592010-09-09 14:50:17 +0200860 if (auto_pin_type == AUTO_PIN_MIC) {
Takashi Iwai23f0c042009-02-26 13:03:58 +0100861 unsigned int pincap;
Takashi Iwai954a29c2010-07-30 10:55:44 +0200862 unsigned int oldval;
863 oldval = snd_hda_codec_read(codec, nid, 0,
864 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
Takashi Iwai1327a322009-03-23 13:07:47 +0100865 pincap = snd_hda_query_pin_caps(codec, nid);
Takashi Iwai23f0c042009-02-26 13:03:58 +0100866 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
Takashi Iwai954a29c2010-07-30 10:55:44 +0200867 /* if the default pin setup is vref50, we give it priority */
868 if ((pincap & AC_PINCAP_VREF_80) && oldval != PIN_VREF50)
Takashi Iwai23f0c042009-02-26 13:03:58 +0100869 val = PIN_VREF80;
Takashi Iwai461c6c32009-05-25 08:06:02 +0200870 else if (pincap & AC_PINCAP_VREF_50)
871 val = PIN_VREF50;
872 else if (pincap & AC_PINCAP_VREF_100)
873 val = PIN_VREF100;
874 else if (pincap & AC_PINCAP_VREF_GRD)
875 val = PIN_VREFGRD;
Takashi Iwai23f0c042009-02-26 13:03:58 +0100876 }
877 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
878}
879
Takashi Iwaif6837bb2010-09-20 14:56:32 +0200880static void alc_fixup_autocfg_pin_nums(struct hda_codec *codec)
881{
882 struct alc_spec *spec = codec->spec;
883 struct auto_pin_cfg *cfg = &spec->autocfg;
884
885 if (!cfg->line_outs) {
886 while (cfg->line_outs < AUTO_CFG_MAX_OUTS &&
887 cfg->line_out_pins[cfg->line_outs])
888 cfg->line_outs++;
889 }
890 if (!cfg->speaker_outs) {
891 while (cfg->speaker_outs < AUTO_CFG_MAX_OUTS &&
892 cfg->speaker_pins[cfg->speaker_outs])
893 cfg->speaker_outs++;
894 }
895 if (!cfg->hp_outs) {
896 while (cfg->hp_outs < AUTO_CFG_MAX_OUTS &&
897 cfg->hp_pins[cfg->hp_outs])
898 cfg->hp_outs++;
899 }
900}
901
Takashi Iwai23f0c042009-02-26 13:03:58 +0100902/*
Takashi Iwaid88897e2008-10-31 15:01:37 +0100903 */
904static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix)
905{
906 if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
907 return;
908 spec->mixers[spec->num_mixers++] = mix;
909}
910
911static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
912{
913 if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
914 return;
915 spec->init_verbs[spec->num_init_verbs++] = verb;
916}
917
918/*
Kailang Yangdf694da2005-12-05 19:42:22 +0100919 * set up from the preset table
920 */
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200921static void setup_preset(struct hda_codec *codec,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200922 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100923{
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200924 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +0100925 int i;
926
927 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100928 add_mixer(spec, preset->mixers[i]);
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100929 spec->cap_mixer = preset->cap_mixer;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200930 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
931 i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100932 add_verb(spec, preset->init_verbs[i]);
Kailang Yangea1fb292008-08-26 12:58:38 +0200933
Kailang Yangdf694da2005-12-05 19:42:22 +0100934 spec->channel_mode = preset->channel_mode;
935 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200936 spec->need_dac_fix = preset->need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200937 spec->const_channel_count = preset->const_channel_count;
Kailang Yangdf694da2005-12-05 19:42:22 +0100938
Hector Martin3b315d72009-06-02 10:54:19 +0200939 if (preset->const_channel_count)
940 spec->multiout.max_channels = preset->const_channel_count;
941 else
942 spec->multiout.max_channels = spec->channel_mode[0].channels;
943 spec->ext_channel_count = spec->channel_mode[0].channels;
Kailang Yangdf694da2005-12-05 19:42:22 +0100944
945 spec->multiout.num_dacs = preset->num_dacs;
946 spec->multiout.dac_nids = preset->dac_nids;
947 spec->multiout.dig_out_nid = preset->dig_out_nid;
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800948 spec->multiout.slave_dig_outs = preset->slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100949 spec->multiout.hp_nid = preset->hp_nid;
Kailang Yangea1fb292008-08-26 12:58:38 +0200950
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200951 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200952 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200953 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100954 spec->input_mux = preset->input_mux;
955
956 spec->num_adc_nids = preset->num_adc_nids;
957 spec->adc_nids = preset->adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100958 spec->capsrc_nids = preset->capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100959 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100960
961 spec->unsol_event = preset->unsol_event;
962 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200963#ifdef CONFIG_SND_HDA_POWER_SAVE
Hector Martinf5de24b2009-12-20 22:51:31 +0100964 spec->power_hook = preset->power_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200965 spec->loopback.amplist = preset->loopbacks;
966#endif
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200967
968 if (preset->setup)
969 preset->setup(codec);
Takashi Iwaif6837bb2010-09-20 14:56:32 +0200970
971 alc_fixup_autocfg_pin_nums(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +0100972}
973
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200974/* Enable GPIO mask and set output */
975static struct hda_verb alc_gpio1_init_verbs[] = {
976 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
977 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
978 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
979 { }
980};
981
982static struct hda_verb alc_gpio2_init_verbs[] = {
983 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
984 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
985 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
986 { }
987};
988
Kailang Yangbdd148a2007-05-08 15:19:08 +0200989static struct hda_verb alc_gpio3_init_verbs[] = {
990 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
991 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
992 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
993 { }
994};
995
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200996/*
997 * Fix hardware PLL issue
998 * On some codecs, the analog PLL gating control must be off while
999 * the default value is 1.
1000 */
1001static void alc_fix_pll(struct hda_codec *codec)
1002{
1003 struct alc_spec *spec = codec->spec;
1004 unsigned int val;
1005
1006 if (!spec->pll_nid)
1007 return;
1008 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
1009 spec->pll_coef_idx);
1010 val = snd_hda_codec_read(codec, spec->pll_nid, 0,
1011 AC_VERB_GET_PROC_COEF, 0);
1012 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
1013 spec->pll_coef_idx);
1014 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
1015 val & ~(1 << spec->pll_coef_bit));
1016}
1017
1018static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
1019 unsigned int coef_idx, unsigned int coef_bit)
1020{
1021 struct alc_spec *spec = codec->spec;
1022 spec->pll_nid = nid;
1023 spec->pll_coef_idx = coef_idx;
1024 spec->pll_coef_bit = coef_bit;
1025 alc_fix_pll(codec);
1026}
1027
Kailang Yang9ad0e492010-09-14 23:22:00 +02001028#ifdef CONFIG_SND_HDA_INPUT_JACK
1029static void alc_free_jack_priv(struct snd_jack *jack)
1030{
1031 struct alc_jack *jacks = jack->private_data;
1032 jacks->nid = 0;
1033 jacks->jack = NULL;
1034}
1035
1036static int alc_add_jack(struct hda_codec *codec,
1037 hda_nid_t nid, int type)
1038{
1039 struct alc_spec *spec;
1040 struct alc_jack *jack;
1041 const char *name;
1042 int err;
1043
1044 spec = codec->spec;
1045 snd_array_init(&spec->jacks, sizeof(*jack), 32);
1046 jack = snd_array_new(&spec->jacks);
1047 if (!jack)
1048 return -ENOMEM;
1049
1050 jack->nid = nid;
1051 jack->type = type;
1052 name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ;
1053
1054 err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
1055 if (err < 0)
1056 return err;
1057 jack->jack->private_data = jack;
1058 jack->jack->private_free = alc_free_jack_priv;
1059 return 0;
1060}
1061
1062static void alc_report_jack(struct hda_codec *codec, hda_nid_t nid)
1063{
1064 struct alc_spec *spec = codec->spec;
1065 struct alc_jack *jacks = spec->jacks.list;
1066
1067 if (jacks) {
1068 int i;
1069 for (i = 0; i < spec->jacks.used; i++) {
1070 if (jacks->nid == nid) {
1071 unsigned int present;
1072 present = snd_hda_jack_detect(codec, nid);
1073
1074 present = (present) ? jacks->type : 0;
1075
1076 snd_jack_report(jacks->jack, present);
1077 }
1078 jacks++;
1079 }
1080 }
1081}
1082
1083static int alc_init_jacks(struct hda_codec *codec)
1084{
1085 struct alc_spec *spec = codec->spec;
1086 int err;
1087 unsigned int hp_nid = spec->autocfg.hp_pins[0];
1088 unsigned int mic_nid = spec->ext_mic.pin;
1089
Takashi Iwai265a0242010-09-21 11:26:21 +02001090 if (hp_nid) {
1091 err = alc_add_jack(codec, hp_nid, SND_JACK_HEADPHONE);
1092 if (err < 0)
1093 return err;
1094 alc_report_jack(codec, hp_nid);
1095 }
Kailang Yang9ad0e492010-09-14 23:22:00 +02001096
Takashi Iwai265a0242010-09-21 11:26:21 +02001097 if (mic_nid) {
1098 err = alc_add_jack(codec, mic_nid, SND_JACK_MICROPHONE);
1099 if (err < 0)
1100 return err;
1101 alc_report_jack(codec, mic_nid);
1102 }
Kailang Yang9ad0e492010-09-14 23:22:00 +02001103
1104 return 0;
1105}
1106#else
1107static inline void alc_report_jack(struct hda_codec *codec, hda_nid_t nid)
1108{
1109}
1110
1111static inline int alc_init_jacks(struct hda_codec *codec)
1112{
1113 return 0;
1114}
1115#endif
1116
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001117static void alc_automute_speaker(struct hda_codec *codec, int pinctl)
Kailang Yangc9b58002007-10-16 14:30:01 +02001118{
1119 struct alc_spec *spec = codec->spec;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001120 unsigned int mute;
1121 hda_nid_t nid;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001122 int i;
Kailang Yangc9b58002007-10-16 14:30:01 +02001123
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001124 spec->jack_present = 0;
1125 for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
1126 nid = spec->autocfg.hp_pins[i];
1127 if (!nid)
1128 break;
1129 if (snd_hda_jack_detect(codec, nid)) {
1130 spec->jack_present = 1;
1131 break;
1132 }
Kailang Yang9ad0e492010-09-14 23:22:00 +02001133 alc_report_jack(codec, spec->autocfg.hp_pins[i]);
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001134 }
1135
1136 mute = spec->jack_present ? HDA_AMP_MUTE : 0;
1137 /* Toggle internal speakers muting */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001138 for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
1139 nid = spec->autocfg.speaker_pins[i];
1140 if (!nid)
1141 break;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001142 if (pinctl) {
1143 snd_hda_codec_write(codec, nid, 0,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001144 AC_VERB_SET_PIN_WIDGET_CONTROL,
1145 spec->jack_present ? 0 : PIN_OUT);
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001146 } else {
1147 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
1148 HDA_AMP_MUTE, mute);
1149 }
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001150 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001151}
1152
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001153static void alc_automute_pin(struct hda_codec *codec)
1154{
1155 alc_automute_speaker(codec, 1);
1156}
1157
Takashi Iwai6c819492009-08-10 18:47:44 +02001158static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
1159 hda_nid_t nid)
1160{
1161 hda_nid_t conn[HDA_MAX_NUM_INPUTS];
1162 int i, nums;
1163
1164 nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
1165 for (i = 0; i < nums; i++)
1166 if (conn[i] == nid)
1167 return i;
1168 return -1;
1169}
1170
Takashi Iwai840b64c2010-07-13 22:49:01 +02001171/* switch the current ADC according to the jack state */
1172static void alc_dual_mic_adc_auto_switch(struct hda_codec *codec)
1173{
1174 struct alc_spec *spec = codec->spec;
1175 unsigned int present;
1176 hda_nid_t new_adc;
1177
1178 present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
1179 if (present)
1180 spec->cur_adc_idx = 1;
1181 else
1182 spec->cur_adc_idx = 0;
1183 new_adc = spec->adc_nids[spec->cur_adc_idx];
1184 if (spec->cur_adc && spec->cur_adc != new_adc) {
1185 /* stream is running, let's swap the current ADC */
Takashi Iwaif0cea792010-08-13 11:56:53 +02001186 __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
Takashi Iwai840b64c2010-07-13 22:49:01 +02001187 spec->cur_adc = new_adc;
1188 snd_hda_codec_setup_stream(codec, new_adc,
1189 spec->cur_adc_stream_tag, 0,
1190 spec->cur_adc_format);
1191 }
1192}
1193
Kailang Yang7fb0d782008-10-15 11:12:35 +02001194static void alc_mic_automute(struct hda_codec *codec)
1195{
1196 struct alc_spec *spec = codec->spec;
Takashi Iwai6c819492009-08-10 18:47:44 +02001197 struct alc_mic_route *dead, *alive;
1198 unsigned int present, type;
1199 hda_nid_t cap_nid;
Kailang Yang7fb0d782008-10-15 11:12:35 +02001200
Takashi Iwaib59bdf32009-08-11 09:47:30 +02001201 if (!spec->auto_mic)
1202 return;
Takashi Iwai6c819492009-08-10 18:47:44 +02001203 if (!spec->int_mic.pin || !spec->ext_mic.pin)
1204 return;
1205 if (snd_BUG_ON(!spec->adc_nids))
1206 return;
1207
Takashi Iwai840b64c2010-07-13 22:49:01 +02001208 if (spec->dual_adc_switch) {
1209 alc_dual_mic_adc_auto_switch(codec);
1210 return;
1211 }
1212
Takashi Iwai6c819492009-08-10 18:47:44 +02001213 cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0];
1214
Wu Fengguang864f92b2009-11-18 12:38:02 +08001215 present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
Takashi Iwai6c819492009-08-10 18:47:44 +02001216 if (present) {
1217 alive = &spec->ext_mic;
1218 dead = &spec->int_mic;
1219 } else {
1220 alive = &spec->int_mic;
1221 dead = &spec->ext_mic;
1222 }
1223
Takashi Iwai6c819492009-08-10 18:47:44 +02001224 type = get_wcaps_type(get_wcaps(codec, cap_nid));
1225 if (type == AC_WID_AUD_MIX) {
1226 /* Matrix-mixer style (e.g. ALC882) */
1227 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1228 alive->mux_idx,
1229 HDA_AMP_MUTE, 0);
1230 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1231 dead->mux_idx,
1232 HDA_AMP_MUTE, HDA_AMP_MUTE);
1233 } else {
1234 /* MUX style (e.g. ALC880) */
1235 snd_hda_codec_write_cache(codec, cap_nid, 0,
1236 AC_VERB_SET_CONNECT_SEL,
1237 alive->mux_idx);
1238 }
Kailang Yang9ad0e492010-09-14 23:22:00 +02001239 alc_report_jack(codec, spec->ext_mic.pin);
Takashi Iwai6c819492009-08-10 18:47:44 +02001240
1241 /* FIXME: analog mixer */
Kailang Yang7fb0d782008-10-15 11:12:35 +02001242}
1243
Kailang Yangc9b58002007-10-16 14:30:01 +02001244/* unsolicited event for HP jack sensing */
1245static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
1246{
1247 if (codec->vendor_id == 0x10ec0880)
1248 res >>= 28;
1249 else
1250 res >>= 26;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001251 switch (res) {
1252 case ALC880_HP_EVENT:
1253 alc_automute_pin(codec);
1254 break;
1255 case ALC880_MIC_EVENT:
Kailang Yang7fb0d782008-10-15 11:12:35 +02001256 alc_mic_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001257 break;
1258 }
Kailang Yang7fb0d782008-10-15 11:12:35 +02001259}
1260
1261static void alc_inithook(struct hda_codec *codec)
1262{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001263 alc_automute_pin(codec);
Kailang Yang7fb0d782008-10-15 11:12:35 +02001264 alc_mic_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +02001265}
1266
Kailang Yangf9423e72008-05-27 12:32:25 +02001267/* additional initialization for ALC888 variants */
1268static void alc888_coef_init(struct hda_codec *codec)
1269{
1270 unsigned int tmp;
1271
1272 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
1273 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
1274 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
Takashi Iwai37db6232009-03-05 09:40:16 +01001275 if ((tmp & 0xf0) == 0x20)
Kailang Yangf9423e72008-05-27 12:32:25 +02001276 /* alc888S-VC */
1277 snd_hda_codec_read(codec, 0x20, 0,
1278 AC_VERB_SET_PROC_COEF, 0x830);
1279 else
1280 /* alc888-VB */
1281 snd_hda_codec_read(codec, 0x20, 0,
1282 AC_VERB_SET_PROC_COEF, 0x3030);
1283}
1284
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02001285static void alc889_coef_init(struct hda_codec *codec)
1286{
1287 unsigned int tmp;
1288
1289 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
1290 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
1291 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
1292 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, tmp|0x2010);
1293}
1294
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001295/* turn on/off EAPD control (only if available) */
1296static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on)
1297{
1298 if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
1299 return;
1300 if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
1301 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
1302 on ? 2 : 0);
1303}
1304
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001305static void alc_auto_init_amp(struct hda_codec *codec, int type)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001306{
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001307 unsigned int tmp;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001308
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001309 switch (type) {
1310 case ALC_INIT_GPIO1:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001311 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
1312 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001313 case ALC_INIT_GPIO2:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001314 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
1315 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001316 case ALC_INIT_GPIO3:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001317 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
1318 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001319 case ALC_INIT_DEFAULT:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001320 switch (codec->vendor_id) {
Kailang Yangc9b58002007-10-16 14:30:01 +02001321 case 0x10ec0260:
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001322 set_eapd(codec, 0x0f, 1);
1323 set_eapd(codec, 0x10, 1);
Kailang Yangc9b58002007-10-16 14:30:01 +02001324 break;
1325 case 0x10ec0262:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001326 case 0x10ec0267:
1327 case 0x10ec0268:
Kailang Yangc9b58002007-10-16 14:30:01 +02001328 case 0x10ec0269:
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001329 case 0x10ec0270:
Takashi Iwaic6e8f2d2009-02-06 12:45:52 +01001330 case 0x10ec0272:
Kailang Yangf9423e72008-05-27 12:32:25 +02001331 case 0x10ec0660:
1332 case 0x10ec0662:
1333 case 0x10ec0663:
Kailang Yangc9b58002007-10-16 14:30:01 +02001334 case 0x10ec0862:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001335 case 0x10ec0889:
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001336 set_eapd(codec, 0x14, 1);
1337 set_eapd(codec, 0x15, 1);
Kailang Yangc9b58002007-10-16 14:30:01 +02001338 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +02001339 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001340 switch (codec->vendor_id) {
1341 case 0x10ec0260:
1342 snd_hda_codec_write(codec, 0x1a, 0,
1343 AC_VERB_SET_COEF_INDEX, 7);
1344 tmp = snd_hda_codec_read(codec, 0x1a, 0,
1345 AC_VERB_GET_PROC_COEF, 0);
1346 snd_hda_codec_write(codec, 0x1a, 0,
1347 AC_VERB_SET_COEF_INDEX, 7);
1348 snd_hda_codec_write(codec, 0x1a, 0,
1349 AC_VERB_SET_PROC_COEF,
1350 tmp | 0x2010);
1351 break;
1352 case 0x10ec0262:
1353 case 0x10ec0880:
1354 case 0x10ec0882:
1355 case 0x10ec0883:
1356 case 0x10ec0885:
Takashi Iwai4a5a4c52009-02-06 12:46:59 +01001357 case 0x10ec0887:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001358 case 0x10ec0889:
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02001359 alc889_coef_init(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +02001360 break;
Kailang Yangf9423e72008-05-27 12:32:25 +02001361 case 0x10ec0888:
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001362 alc888_coef_init(codec);
Kailang Yangf9423e72008-05-27 12:32:25 +02001363 break;
Takashi Iwai0aea7782010-01-25 15:44:11 +01001364#if 0 /* XXX: This may cause the silent output on speaker on some machines */
Kailang Yangc9b58002007-10-16 14:30:01 +02001365 case 0x10ec0267:
1366 case 0x10ec0268:
1367 snd_hda_codec_write(codec, 0x20, 0,
1368 AC_VERB_SET_COEF_INDEX, 7);
1369 tmp = snd_hda_codec_read(codec, 0x20, 0,
1370 AC_VERB_GET_PROC_COEF, 0);
1371 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001372 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001373 snd_hda_codec_write(codec, 0x20, 0,
1374 AC_VERB_SET_PROC_COEF,
1375 tmp | 0x3000);
1376 break;
Takashi Iwai0aea7782010-01-25 15:44:11 +01001377#endif /* XXX */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001378 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001379 break;
1380 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001381}
Kailang Yangea1fb292008-08-26 12:58:38 +02001382
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001383static void alc_init_auto_hp(struct hda_codec *codec)
1384{
1385 struct alc_spec *spec = codec->spec;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001386 struct auto_pin_cfg *cfg = &spec->autocfg;
1387 int i;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001388
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001389 if (!cfg->hp_pins[0]) {
1390 if (cfg->line_out_type != AUTO_PIN_HP_OUT)
Kailang Yangc9b58002007-10-16 14:30:01 +02001391 return;
1392 }
1393
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001394 if (!cfg->speaker_pins[0]) {
1395 if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
1396 return;
1397 memcpy(cfg->speaker_pins, cfg->line_out_pins,
1398 sizeof(cfg->speaker_pins));
1399 cfg->speaker_outs = cfg->line_outs;
1400 }
1401
1402 if (!cfg->hp_pins[0]) {
1403 memcpy(cfg->hp_pins, cfg->line_out_pins,
1404 sizeof(cfg->hp_pins));
1405 cfg->hp_outs = cfg->line_outs;
1406 }
1407
1408 for (i = 0; i < cfg->hp_outs; i++) {
1409 snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
1410 cfg->hp_pins[i]);
1411 snd_hda_codec_write_cache(codec, cfg->hp_pins[i], 0,
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001412 AC_VERB_SET_UNSOLICITED_ENABLE,
1413 AC_USRSP_EN | ALC880_HP_EVENT);
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001414 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001415 spec->unsol_event = alc_sku_unsol_event;
1416}
1417
Takashi Iwai6c819492009-08-10 18:47:44 +02001418static void alc_init_auto_mic(struct hda_codec *codec)
1419{
1420 struct alc_spec *spec = codec->spec;
1421 struct auto_pin_cfg *cfg = &spec->autocfg;
1422 hda_nid_t fixed, ext;
1423 int i;
1424
1425 /* there must be only two mic inputs exclusively */
Takashi Iwai66ceeb62010-08-30 13:05:52 +02001426 for (i = 0; i < cfg->num_inputs; i++)
Takashi Iwai86e29592010-09-09 14:50:17 +02001427 if (cfg->inputs[i].type >= AUTO_PIN_LINE_IN)
Takashi Iwai6c819492009-08-10 18:47:44 +02001428 return;
1429
1430 fixed = ext = 0;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02001431 for (i = 0; i < cfg->num_inputs; i++) {
1432 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai6c819492009-08-10 18:47:44 +02001433 unsigned int defcfg;
Takashi Iwai6c819492009-08-10 18:47:44 +02001434 defcfg = snd_hda_codec_get_pincfg(codec, nid);
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001435 switch (snd_hda_get_input_pin_attr(defcfg)) {
1436 case INPUT_PIN_ATTR_INT:
Takashi Iwai6c819492009-08-10 18:47:44 +02001437 if (fixed)
1438 return; /* already occupied */
1439 fixed = nid;
1440 break;
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001441 case INPUT_PIN_ATTR_UNUSED:
1442 return; /* invalid entry */
1443 default:
Takashi Iwai6c819492009-08-10 18:47:44 +02001444 if (ext)
1445 return; /* already occupied */
1446 ext = nid;
1447 break;
Takashi Iwai6c819492009-08-10 18:47:44 +02001448 }
1449 }
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01001450 if (!ext || !fixed)
1451 return;
Takashi Iwai6c819492009-08-10 18:47:44 +02001452 if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP))
1453 return; /* no unsol support */
1454 snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x\n",
1455 ext, fixed);
1456 spec->ext_mic.pin = ext;
1457 spec->int_mic.pin = fixed;
1458 spec->ext_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
1459 spec->int_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
1460 spec->auto_mic = 1;
1461 snd_hda_codec_write_cache(codec, spec->ext_mic.pin, 0,
1462 AC_VERB_SET_UNSOLICITED_ENABLE,
1463 AC_USRSP_EN | ALC880_MIC_EVENT);
1464 spec->unsol_event = alc_sku_unsol_event;
1465}
1466
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) {
Takashi Iwai01fdf182010-09-24 09:09:42 +02001762 dig_nid = codec->start_nid;
1763 for (i = 0; i < codec->num_nodes; i++, dig_nid++) {
1764 unsigned int wcaps = get_wcaps(codec, dig_nid);
1765 if (get_wcaps_type(wcaps) != AC_WID_AUD_IN)
1766 continue;
1767 if (!(wcaps & AC_WCAP_DIGITAL))
1768 continue;
1769 if (!(wcaps & AC_WCAP_CONN_LIST))
1770 continue;
1771 err = get_connection_index(codec, dig_nid,
1772 spec->autocfg.dig_in_pin);
1773 if (err >= 0) {
1774 spec->dig_in_nid = dig_nid;
1775 break;
1776 }
1777 }
Takashi Iwai757899a2010-07-30 10:48:14 +02001778 }
1779}
1780
Takashi Iwaif95474e2007-07-10 00:47:43 +02001781/*
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001782 * ALC888
1783 */
1784
1785/*
1786 * 2ch mode
1787 */
1788static struct hda_verb alc888_4ST_ch2_intel_init[] = {
1789/* Mic-in jack as mic in */
1790 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1791 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1792/* Line-in jack as Line in */
1793 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1794 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1795/* Line-Out as Front */
1796 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
1797 { } /* end */
1798};
1799
1800/*
1801 * 4ch mode
1802 */
1803static struct hda_verb alc888_4ST_ch4_intel_init[] = {
1804/* Mic-in jack as mic in */
1805 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1806 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1807/* Line-in jack as Surround */
1808 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1809 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1810/* Line-Out as Front */
1811 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
1812 { } /* end */
1813};
1814
1815/*
1816 * 6ch mode
1817 */
1818static struct hda_verb alc888_4ST_ch6_intel_init[] = {
1819/* Mic-in jack as CLFE */
1820 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1821 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1822/* Line-in jack as Surround */
1823 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1824 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1825/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */
1826 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1827 { } /* end */
1828};
1829
1830/*
1831 * 8ch mode
1832 */
1833static struct hda_verb alc888_4ST_ch8_intel_init[] = {
1834/* Mic-in jack as CLFE */
1835 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1836 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1837/* Line-in jack as Surround */
1838 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1839 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1840/* Line-Out as Side */
1841 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1842 { } /* end */
1843};
1844
1845static struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
1846 { 2, alc888_4ST_ch2_intel_init },
1847 { 4, alc888_4ST_ch4_intel_init },
1848 { 6, alc888_4ST_ch6_intel_init },
1849 { 8, alc888_4ST_ch8_intel_init },
1850};
1851
1852/*
1853 * ALC888 Fujitsu Siemens Amillo xa3530
1854 */
1855
1856static struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
1857/* Front Mic: set to PIN_IN (empty by default) */
1858 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1859/* Connect Internal HP to Front */
1860 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1861 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1862 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1863/* Connect Bass HP to Front */
1864 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1865 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1866 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1867/* Connect Line-Out side jack (SPDIF) to Side */
1868 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1869 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1870 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1871/* Connect Mic jack to CLFE */
1872 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1873 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1874 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
1875/* Connect Line-in jack to Surround */
1876 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1877 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1878 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
1879/* Connect HP out jack to Front */
1880 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1881 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1882 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
1883/* Enable unsolicited event for HP jack and Line-out jack */
1884 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1885 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1886 {}
1887};
1888
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001889static void alc_automute_amp(struct hda_codec *codec)
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001890{
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001891 alc_automute_speaker(codec, 0);
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001892}
1893
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001894static void alc_automute_amp_unsol_event(struct hda_codec *codec,
1895 unsigned int res)
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001896{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001897 if (codec->vendor_id == 0x10ec0880)
1898 res >>= 28;
1899 else
1900 res >>= 26;
1901 if (res == ALC880_HP_EVENT)
1902 alc_automute_amp(codec);
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001903}
1904
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001905static void alc889_automute_setup(struct hda_codec *codec)
Wu Fengguang6732bd02009-07-30 09:19:14 +02001906{
1907 struct alc_spec *spec = codec->spec;
1908
1909 spec->autocfg.hp_pins[0] = 0x15;
1910 spec->autocfg.speaker_pins[0] = 0x14;
1911 spec->autocfg.speaker_pins[1] = 0x16;
1912 spec->autocfg.speaker_pins[2] = 0x17;
1913 spec->autocfg.speaker_pins[3] = 0x19;
1914 spec->autocfg.speaker_pins[4] = 0x1a;
Wu Fengguang6732bd02009-07-30 09:19:14 +02001915}
1916
1917static void alc889_intel_init_hook(struct hda_codec *codec)
1918{
1919 alc889_coef_init(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001920 alc_automute_amp(codec);
Wu Fengguang6732bd02009-07-30 09:19:14 +02001921}
1922
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001923static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001924{
1925 struct alc_spec *spec = codec->spec;
1926
1927 spec->autocfg.hp_pins[0] = 0x17; /* line-out */
1928 spec->autocfg.hp_pins[1] = 0x1b; /* hp */
1929 spec->autocfg.speaker_pins[0] = 0x14; /* speaker */
1930 spec->autocfg.speaker_pins[1] = 0x15; /* bass */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001931}
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001932
1933/*
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001934 * ALC888 Acer Aspire 4930G model
1935 */
1936
1937static struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
1938/* Front Mic: set to PIN_IN (empty by default) */
1939 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1940/* Unselect Front Mic by default in input mixer 3 */
1941 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001942/* Enable unsolicited event for HP jack */
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001943 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1944/* Connect Internal HP to front */
1945 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1946 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1947 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1948/* Connect HP out to front */
1949 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1950 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1951 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1952 { }
1953};
1954
Hector Martin3b315d72009-06-02 10:54:19 +02001955/*
Tony Vroond2fd4b02009-06-21 00:40:10 +01001956 * ALC888 Acer Aspire 6530G model
1957 */
1958
1959static struct hda_verb alc888_acer_aspire_6530g_verbs[] = {
Tony Vroond1284182010-04-05 16:30:43 +01001960/* Route to built-in subwoofer as well as speakers */
1961 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1962 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1963 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1964 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Tony Vroond2fd4b02009-06-21 00:40:10 +01001965/* Bias voltage on for external mic port */
1966 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
Emilio López320d5922009-06-25 08:18:44 +02001967/* Front Mic: set to PIN_IN (empty by default) */
1968 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1969/* Unselect Front Mic by default in input mixer 3 */
1970 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Tony Vroond2fd4b02009-06-21 00:40:10 +01001971/* Enable unsolicited event for HP jack */
1972 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1973/* Enable speaker output */
1974 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1975 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Tony Vroond1284182010-04-05 16:30:43 +01001976 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Tony Vroond2fd4b02009-06-21 00:40:10 +01001977/* Enable headphone output */
1978 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
1979 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1980 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Tony Vroond1284182010-04-05 16:30:43 +01001981 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
Tony Vroond2fd4b02009-06-21 00:40:10 +01001982 { }
1983};
1984
1985/*
Hector Martin018df412009-06-04 00:13:40 +02001986 * ALC889 Acer Aspire 8930G model
Hector Martin3b315d72009-06-02 10:54:19 +02001987 */
1988
Hector Martin018df412009-06-04 00:13:40 +02001989static struct hda_verb alc889_acer_aspire_8930g_verbs[] = {
Hector Martin3b315d72009-06-02 10:54:19 +02001990/* Front Mic: set to PIN_IN (empty by default) */
1991 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1992/* Unselect Front Mic by default in input mixer 3 */
1993 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
1994/* Enable unsolicited event for HP jack */
1995 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1996/* Connect Internal Front to Front */
1997 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1998 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1999 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
2000/* Connect Internal Rear to Rear */
2001 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2002 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2003 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
2004/* Connect Internal CLFE to CLFE */
2005 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2006 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2007 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
2008/* Connect HP out to Front */
Hector Martin018df412009-06-04 00:13:40 +02002009 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
Hector Martin3b315d72009-06-02 10:54:19 +02002010 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2011 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
2012/* Enable all DACs */
2013/* DAC DISABLE/MUTE 1? */
2014/* setting bits 1-5 disables DAC nids 0x02-0x06 apparently. Init=0x38 */
2015 {0x20, AC_VERB_SET_COEF_INDEX, 0x03},
2016 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
2017/* DAC DISABLE/MUTE 2? */
2018/* some bit here disables the other DACs. Init=0x4900 */
2019 {0x20, AC_VERB_SET_COEF_INDEX, 0x08},
2020 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
Hector Martin018df412009-06-04 00:13:40 +02002021/* DMIC fix
2022 * This laptop has a stereo digital microphone. The mics are only 1cm apart
2023 * which makes the stereo useless. However, either the mic or the ALC889
2024 * makes the signal become a difference/sum signal instead of standard
2025 * stereo, which is annoying. So instead we flip this bit which makes the
2026 * codec replicate the sum signal to both channels, turning it into a
2027 * normal mono mic.
2028 */
2029/* DMIC_CONTROL? Init value = 0x0001 */
2030 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
2031 {0x20, AC_VERB_SET_PROC_COEF, 0x0003},
Hector Martin3b315d72009-06-02 10:54:19 +02002032 { }
2033};
2034
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002035static struct hda_input_mux alc888_2_capture_sources[2] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002036 /* Front mic only available on one ADC */
2037 {
2038 .num_items = 4,
2039 .items = {
2040 { "Mic", 0x0 },
2041 { "Line", 0x2 },
2042 { "CD", 0x4 },
2043 { "Front Mic", 0xb },
2044 },
2045 },
2046 {
2047 .num_items = 3,
2048 .items = {
2049 { "Mic", 0x0 },
2050 { "Line", 0x2 },
2051 { "CD", 0x4 },
2052 },
2053 }
2054};
2055
Tony Vroond2fd4b02009-06-21 00:40:10 +01002056static struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
2057 /* Interal mic only available on one ADC */
2058 {
Tony Vroon684a8842009-06-26 09:27:50 +01002059 .num_items = 5,
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 { "Int Mic", 0xb },
2066 },
2067 },
2068 {
Tony Vroon684a8842009-06-26 09:27:50 +01002069 .num_items = 4,
Tony Vroond2fd4b02009-06-21 00:40:10 +01002070 .items = {
2071 { "Ext Mic", 0x0 },
Tony Vroon684a8842009-06-26 09:27:50 +01002072 { "Line In", 0x2 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002073 { "CD", 0x4 },
Tony Vroon684a8842009-06-26 09:27:50 +01002074 { "Input Mix", 0xa },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002075 },
2076 }
2077};
2078
Hector Martin018df412009-06-04 00:13:40 +02002079static struct hda_input_mux alc889_capture_sources[3] = {
2080 /* Digital mic only available on first "ADC" */
2081 {
2082 .num_items = 5,
2083 .items = {
2084 { "Mic", 0x0 },
2085 { "Line", 0x2 },
2086 { "CD", 0x4 },
2087 { "Front Mic", 0xb },
2088 { "Input Mix", 0xa },
2089 },
2090 },
2091 {
2092 .num_items = 4,
2093 .items = {
2094 { "Mic", 0x0 },
2095 { "Line", 0x2 },
2096 { "CD", 0x4 },
2097 { "Input Mix", 0xa },
2098 },
2099 },
2100 {
2101 .num_items = 4,
2102 .items = {
2103 { "Mic", 0x0 },
2104 { "Line", 0x2 },
2105 { "CD", 0x4 },
2106 { "Input Mix", 0xa },
2107 },
2108 }
2109};
2110
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002111static struct snd_kcontrol_new alc888_base_mixer[] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002112 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2113 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2114 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2115 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2116 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
2117 HDA_OUTPUT),
2118 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2119 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2120 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2121 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2122 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
2123 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2124 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2125 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2126 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2127 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2128 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
2129 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002130 { } /* end */
2131};
2132
Hector Martin556eea92009-12-20 22:51:23 +01002133static struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = {
2134 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2135 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2136 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2137 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2138 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
2139 HDA_OUTPUT),
2140 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2141 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2142 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2143 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2144 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2145 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2146 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
2147 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2148 { } /* end */
2149};
2150
2151
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002152static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec)
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002153{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002154 struct alc_spec *spec = codec->spec;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002155
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002156 spec->autocfg.hp_pins[0] = 0x15;
2157 spec->autocfg.speaker_pins[0] = 0x14;
Łukasz Wojniłowicz7cef4cf2009-11-20 12:14:35 +01002158 spec->autocfg.speaker_pins[1] = 0x16;
2159 spec->autocfg.speaker_pins[2] = 0x17;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002160}
2161
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002162static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec)
Emilio López320d5922009-06-25 08:18:44 +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] = 0x17;
Emilio López320d5922009-06-25 08:18:44 +02002170}
2171
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002172static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
Hector Martin3b315d72009-06-02 10:54:19 +02002173{
2174 struct alc_spec *spec = codec->spec;
2175
2176 spec->autocfg.hp_pins[0] = 0x15;
2177 spec->autocfg.speaker_pins[0] = 0x14;
2178 spec->autocfg.speaker_pins[1] = 0x16;
2179 spec->autocfg.speaker_pins[2] = 0x1b;
Hector Martin3b315d72009-06-02 10:54:19 +02002180}
2181
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002182/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002183 * ALC880 3-stack model
2184 *
2185 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002186 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
2187 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 */
2189
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002190static hda_nid_t alc880_dac_nids[4] = {
2191 /* front, rear, clfe, rear_surr */
2192 0x02, 0x05, 0x04, 0x03
2193};
2194
2195static hda_nid_t alc880_adc_nids[3] = {
2196 /* ADC0-2 */
2197 0x07, 0x08, 0x09,
2198};
2199
2200/* The datasheet says the node 0x07 is connected from inputs,
2201 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +01002202 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002204static hda_nid_t alc880_adc_nids_alt[2] = {
2205 /* ADC1-2 */
2206 0x08, 0x09,
2207};
2208
2209#define ALC880_DIGOUT_NID 0x06
2210#define ALC880_DIGIN_NID 0x0a
2211
2212static struct hda_input_mux alc880_capture_source = {
2213 .num_items = 4,
2214 .items = {
2215 { "Mic", 0x0 },
2216 { "Front Mic", 0x3 },
2217 { "Line", 0x2 },
2218 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002220};
2221
2222/* channel source setting (2/6 channel selection for 3-stack) */
2223/* 2ch mode */
2224static struct hda_verb alc880_threestack_ch2_init[] = {
2225 /* set line-in to input, mute it */
2226 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2227 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2228 /* set mic-in to input vref 80%, mute it */
2229 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2230 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 { } /* end */
2232};
2233
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002234/* 6ch mode */
2235static struct hda_verb alc880_threestack_ch6_init[] = {
2236 /* set line-in to output, unmute it */
2237 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2238 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2239 /* set mic-in to output, unmute it */
2240 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2241 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2242 { } /* end */
2243};
2244
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002245static struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002246 { 2, alc880_threestack_ch2_init },
2247 { 6, alc880_threestack_ch6_init },
2248};
2249
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002250static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002251 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002252 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02002253 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002254 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02002255 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2256 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002257 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2258 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2260 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2261 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2262 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2263 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2264 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2265 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
2266 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002268 {
2269 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2270 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002271 .info = alc_ch_mode_info,
2272 .get = alc_ch_mode_get,
2273 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002274 },
2275 { } /* end */
2276};
2277
2278/* capture mixer elements */
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002279static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
2280 struct snd_ctl_elem_info *uinfo)
2281{
2282 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2283 struct alc_spec *spec = codec->spec;
2284 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002285
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002286 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002287 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
2288 HDA_INPUT);
2289 err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002290 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002291 return err;
2292}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002294static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
2295 unsigned int size, unsigned int __user *tlv)
2296{
2297 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2298 struct alc_spec *spec = codec->spec;
2299 int err;
2300
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002301 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002302 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
2303 HDA_INPUT);
2304 err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002305 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002306 return err;
2307}
2308
2309typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
2310 struct snd_ctl_elem_value *ucontrol);
2311
2312static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
2313 struct snd_ctl_elem_value *ucontrol,
2314 getput_call_t func)
2315{
2316 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2317 struct alc_spec *spec = codec->spec;
2318 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
2319 int err;
2320
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002321 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002322 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[adc_idx],
2323 3, 0, HDA_INPUT);
2324 err = func(kcontrol, ucontrol);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002325 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002326 return err;
2327}
2328
2329static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
2330 struct snd_ctl_elem_value *ucontrol)
2331{
2332 return alc_cap_getput_caller(kcontrol, ucontrol,
2333 snd_hda_mixer_amp_volume_get);
2334}
2335
2336static int alc_cap_vol_put(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_volume_put);
2341}
2342
2343/* capture mixer elements */
2344#define alc_cap_sw_info snd_ctl_boolean_stereo_info
2345
2346static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
2347 struct snd_ctl_elem_value *ucontrol)
2348{
2349 return alc_cap_getput_caller(kcontrol, ucontrol,
2350 snd_hda_mixer_amp_switch_get);
2351}
2352
2353static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
2354 struct snd_ctl_elem_value *ucontrol)
2355{
2356 return alc_cap_getput_caller(kcontrol, ucontrol,
2357 snd_hda_mixer_amp_switch_put);
2358}
2359
Takashi Iwaia23b6882009-03-23 15:21:36 +01002360#define _DEFINE_CAPMIX(num) \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002361 { \
2362 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2363 .name = "Capture Switch", \
2364 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
2365 .count = num, \
2366 .info = alc_cap_sw_info, \
2367 .get = alc_cap_sw_get, \
2368 .put = alc_cap_sw_put, \
2369 }, \
2370 { \
2371 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2372 .name = "Capture Volume", \
2373 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
2374 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
2375 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
2376 .count = num, \
2377 .info = alc_cap_vol_info, \
2378 .get = alc_cap_vol_get, \
2379 .put = alc_cap_vol_put, \
2380 .tlv = { .c = alc_cap_vol_tlv }, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002381 }
2382
2383#define _DEFINE_CAPSRC(num) \
Takashi Iwai3c3e9892008-10-31 17:48:56 +01002384 { \
2385 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2386 /* .name = "Capture Source", */ \
2387 .name = "Input Source", \
2388 .count = num, \
2389 .info = alc_mux_enum_info, \
2390 .get = alc_mux_enum_get, \
2391 .put = alc_mux_enum_put, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002392 }
2393
2394#define DEFINE_CAPMIX(num) \
2395static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
2396 _DEFINE_CAPMIX(num), \
2397 _DEFINE_CAPSRC(num), \
2398 { } /* end */ \
2399}
2400
2401#define DEFINE_CAPMIX_NOSRC(num) \
2402static struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
2403 _DEFINE_CAPMIX(num), \
2404 { } /* end */ \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002405}
2406
2407/* up to three ADCs */
2408DEFINE_CAPMIX(1);
2409DEFINE_CAPMIX(2);
2410DEFINE_CAPMIX(3);
Takashi Iwaia23b6882009-03-23 15:21:36 +01002411DEFINE_CAPMIX_NOSRC(1);
2412DEFINE_CAPMIX_NOSRC(2);
2413DEFINE_CAPMIX_NOSRC(3);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002414
2415/*
2416 * ALC880 5-stack model
2417 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002418 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
2419 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002420 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
2421 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
2422 */
2423
2424/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002425static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002426 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002427 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428 { } /* end */
2429};
2430
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002431/* channel source setting (6/8 channel selection for 5-stack) */
2432/* 6ch mode */
2433static struct hda_verb alc880_fivestack_ch6_init[] = {
2434 /* set line-in to input, mute it */
2435 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2436 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002437 { } /* end */
2438};
2439
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002440/* 8ch mode */
2441static struct hda_verb alc880_fivestack_ch8_init[] = {
2442 /* set line-in to output, unmute it */
2443 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2444 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2445 { } /* end */
2446};
2447
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002448static struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002449 { 6, alc880_fivestack_ch6_init },
2450 { 8, alc880_fivestack_ch8_init },
2451};
2452
2453
2454/*
2455 * ALC880 6-stack model
2456 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002457 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
2458 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002459 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
2460 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
2461 */
2462
2463static hda_nid_t alc880_6st_dac_nids[4] = {
2464 /* front, rear, clfe, rear_surr */
2465 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002466};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002467
2468static struct hda_input_mux alc880_6stack_capture_source = {
2469 .num_items = 4,
2470 .items = {
2471 { "Mic", 0x0 },
2472 { "Front Mic", 0x1 },
2473 { "Line", 0x2 },
2474 { "CD", 0x4 },
2475 },
2476};
2477
2478/* fixed 8-channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002479static struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002480 { 8, NULL },
2481};
2482
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002483static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002484 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002485 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002486 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002487 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002488 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2489 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002490 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2491 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002492 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002493 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002494 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2495 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2496 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2497 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2498 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2499 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2500 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2501 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002502 {
2503 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2504 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002505 .info = alc_ch_mode_info,
2506 .get = alc_ch_mode_get,
2507 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02002508 },
2509 { } /* end */
2510};
2511
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002512
2513/*
2514 * ALC880 W810 model
2515 *
2516 * W810 has rear IO for:
2517 * Front (DAC 02)
2518 * Surround (DAC 03)
2519 * Center/LFE (DAC 04)
2520 * Digital out (06)
2521 *
2522 * The system also has a pair of internal speakers, and a headphone jack.
2523 * These are both connected to Line2 on the codec, hence to DAC 02.
Kailang Yangea1fb292008-08-26 12:58:38 +02002524 *
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002525 * There is a variable resistor to control the speaker or headphone
2526 * volume. This is a hardware-only device without a software API.
2527 *
2528 * Plugging headphones in will disable the internal speakers. This is
2529 * implemented in hardware, not via the driver using jack sense. In
2530 * a similar fashion, plugging into the rear socket marked "front" will
2531 * disable both the speakers and headphones.
2532 *
2533 * For input, there's a microphone jack, and an "audio in" jack.
2534 * These may not do anything useful with this driver yet, because I
2535 * haven't setup any initialization verbs for these yet...
2536 */
2537
2538static hda_nid_t alc880_w810_dac_nids[3] = {
2539 /* front, rear/surround, clfe */
2540 0x02, 0x03, 0x04
2541};
2542
2543/* fixed 6 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002544static struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002545 { 6, NULL }
2546};
2547
2548/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002549static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002550 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002551 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002552 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002553 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002554 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2555 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002556 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2557 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002558 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
2559 { } /* end */
2560};
2561
2562
2563/*
2564 * Z710V model
2565 *
2566 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002567 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
2568 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002569 */
2570
2571static hda_nid_t alc880_z71v_dac_nids[1] = {
2572 0x02
2573};
2574#define ALC880_Z71V_HP_DAC 0x03
2575
2576/* fixed 2 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002577static struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002578 { 2, NULL }
2579};
2580
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002581static struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002582 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002583 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002584 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002585 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002586 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2587 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2588 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2589 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2590 { } /* end */
2591};
2592
2593
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002594/*
2595 * ALC880 F1734 model
2596 *
2597 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
2598 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
2599 */
2600
2601static hda_nid_t alc880_f1734_dac_nids[1] = {
2602 0x03
2603};
2604#define ALC880_F1734_HP_DAC 0x02
2605
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002606static struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002607 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002608 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01002609 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2610 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002611 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2612 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01002613 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2614 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002615 { } /* end */
2616};
2617
Takashi Iwai937b4162008-02-11 14:52:36 +01002618static struct hda_input_mux alc880_f1734_capture_source = {
2619 .num_items = 2,
2620 .items = {
2621 { "Mic", 0x1 },
2622 { "CD", 0x4 },
2623 },
2624};
2625
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002626
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002627/*
2628 * ALC880 ASUS model
2629 *
2630 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
2631 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
2632 * Mic = 0x18, Line = 0x1a
2633 */
2634
2635#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
2636#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
2637
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002638static struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002639 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002640 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002641 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002642 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002643 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2644 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002645 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2646 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002647 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2648 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2649 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2650 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2651 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2652 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002653 {
2654 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2655 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002656 .info = alc_ch_mode_info,
2657 .get = alc_ch_mode_get,
2658 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02002659 },
2660 { } /* end */
2661};
2662
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002663/*
2664 * ALC880 ASUS W1V model
2665 *
2666 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
2667 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
2668 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
2669 */
2670
2671/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002672static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002673 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
2674 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002675 { } /* end */
2676};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002677
Kailang Yangdf694da2005-12-05 19:42:22 +01002678/* TCL S700 */
2679static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
2680 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2681 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
2682 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
2683 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
2684 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
2685 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
2686 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
2687 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
2688 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01002689 { } /* end */
2690};
2691
Kailang Yangccc656c2006-10-17 12:32:26 +02002692/* Uniwill */
2693static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002694 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2695 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2696 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2697 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002698 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2699 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2700 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2701 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2702 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2703 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2704 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2705 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2706 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2707 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2708 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2709 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002710 {
2711 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2712 .name = "Channel Mode",
2713 .info = alc_ch_mode_info,
2714 .get = alc_ch_mode_get,
2715 .put = alc_ch_mode_put,
2716 },
2717 { } /* end */
2718};
2719
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002720static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
2721 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2722 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2723 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2724 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
2725 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2726 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2727 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2728 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2729 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2730 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
2731 { } /* end */
2732};
2733
Kailang Yangccc656c2006-10-17 12:32:26 +02002734static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002735 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2736 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2737 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2738 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002739 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2740 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2741 { } /* end */
2742};
2743
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01002745 * virtual master controls
2746 */
2747
2748/*
2749 * slave controls for virtual master
2750 */
2751static const char *alc_slave_vols[] = {
2752 "Front Playback Volume",
2753 "Surround Playback Volume",
2754 "Center Playback Volume",
2755 "LFE Playback Volume",
2756 "Side Playback Volume",
2757 "Headphone Playback Volume",
2758 "Speaker Playback Volume",
2759 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002760 "Line-Out Playback Volume",
Takashi Iwai26f5df22008-11-03 17:39:46 +01002761 "PCM Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002762 NULL,
2763};
2764
2765static const char *alc_slave_sws[] = {
2766 "Front Playback Switch",
2767 "Surround Playback Switch",
2768 "Center Playback Switch",
2769 "LFE Playback Switch",
2770 "Side Playback Switch",
2771 "Headphone Playback Switch",
2772 "Speaker Playback Switch",
2773 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01002774 "IEC958 Playback Switch",
Takashi Iwai23033b22009-12-08 12:36:52 +01002775 "Line-Out Playback Switch",
2776 "PCM Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002777 NULL,
2778};
2779
2780/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002781 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 */
Takashi Iwai603c4012008-07-30 15:01:44 +02002783
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002784#define NID_MAPPING (-1)
2785
2786#define SUBDEV_SPEAKER_ (0 << 6)
2787#define SUBDEV_HP_ (1 << 6)
2788#define SUBDEV_LINE_ (2 << 6)
2789#define SUBDEV_SPEAKER(x) (SUBDEV_SPEAKER_ | ((x) & 0x3f))
2790#define SUBDEV_HP(x) (SUBDEV_HP_ | ((x) & 0x3f))
2791#define SUBDEV_LINE(x) (SUBDEV_LINE_ | ((x) & 0x3f))
2792
Takashi Iwai603c4012008-07-30 15:01:44 +02002793static void alc_free_kctls(struct hda_codec *codec);
2794
Takashi Iwai67d634c2009-11-16 15:35:59 +01002795#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002796/* additional beep mixers; the actual parameters are overwritten at build */
2797static struct snd_kcontrol_new alc_beep_mixer[] = {
2798 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
Jaroslav Kysela123c07a2009-10-21 14:48:23 +02002799 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002800 { } /* end */
2801};
Takashi Iwai67d634c2009-11-16 15:35:59 +01002802#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002803
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804static int alc_build_controls(struct hda_codec *codec)
2805{
2806 struct alc_spec *spec = codec->spec;
Takashi Iwai2f44f842010-06-22 11:12:32 +02002807 struct snd_kcontrol *kctl = NULL;
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002808 struct snd_kcontrol_new *knew;
2809 int i, j, err;
2810 unsigned int u;
2811 hda_nid_t nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812
2813 for (i = 0; i < spec->num_mixers; i++) {
2814 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
2815 if (err < 0)
2816 return err;
2817 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002818 if (spec->cap_mixer) {
2819 err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
2820 if (err < 0)
2821 return err;
2822 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002824 err = snd_hda_create_spdif_out_ctls(codec,
2825 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 if (err < 0)
2827 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002828 if (!spec->no_analog) {
2829 err = snd_hda_create_spdif_share_sw(codec,
2830 &spec->multiout);
2831 if (err < 0)
2832 return err;
2833 spec->multiout.share_spdif = 1;
2834 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 }
2836 if (spec->dig_in_nid) {
2837 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
2838 if (err < 0)
2839 return err;
2840 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01002841
Takashi Iwai67d634c2009-11-16 15:35:59 +01002842#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002843 /* create beep controls if needed */
2844 if (spec->beep_amp) {
2845 struct snd_kcontrol_new *knew;
2846 for (knew = alc_beep_mixer; knew->name; knew++) {
2847 struct snd_kcontrol *kctl;
2848 kctl = snd_ctl_new1(knew, codec);
2849 if (!kctl)
2850 return -ENOMEM;
2851 kctl->private_value = spec->beep_amp;
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01002852 err = snd_hda_ctl_add(codec, 0, kctl);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002853 if (err < 0)
2854 return err;
2855 }
2856 }
Takashi Iwai67d634c2009-11-16 15:35:59 +01002857#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002858
Takashi Iwai2134ea42008-01-10 16:53:55 +01002859 /* if we have no master control, let's create it */
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002860 if (!spec->no_analog &&
2861 !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002862 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01002863 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002864 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01002865 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002866 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01002867 if (err < 0)
2868 return err;
2869 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002870 if (!spec->no_analog &&
2871 !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002872 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
2873 NULL, alc_slave_sws);
2874 if (err < 0)
2875 return err;
2876 }
2877
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002878 /* assign Capture Source enums to NID */
Takashi Iwaifbe618f2010-06-11 11:24:58 +02002879 if (spec->capsrc_nids || spec->adc_nids) {
2880 kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
2881 if (!kctl)
2882 kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
2883 for (i = 0; kctl && i < kctl->count; i++) {
2884 hda_nid_t *nids = spec->capsrc_nids;
2885 if (!nids)
2886 nids = spec->adc_nids;
2887 err = snd_hda_add_nid(codec, kctl, i, nids[i]);
2888 if (err < 0)
2889 return err;
2890 }
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002891 }
2892 if (spec->cap_mixer) {
2893 const char *kname = kctl ? kctl->id.name : NULL;
2894 for (knew = spec->cap_mixer; knew->name; knew++) {
2895 if (kname && strcmp(knew->name, kname) == 0)
2896 continue;
2897 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
2898 for (i = 0; kctl && i < kctl->count; i++) {
2899 err = snd_hda_add_nid(codec, kctl, i,
2900 spec->adc_nids[i]);
2901 if (err < 0)
2902 return err;
2903 }
2904 }
2905 }
2906
2907 /* other nid->control mapping */
2908 for (i = 0; i < spec->num_mixers; i++) {
2909 for (knew = spec->mixers[i]; knew->name; knew++) {
2910 if (knew->iface != NID_MAPPING)
2911 continue;
2912 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
2913 if (kctl == NULL)
2914 continue;
2915 u = knew->subdevice;
2916 for (j = 0; j < 4; j++, u >>= 8) {
2917 nid = u & 0x3f;
2918 if (nid == 0)
2919 continue;
2920 switch (u & 0xc0) {
2921 case SUBDEV_SPEAKER_:
2922 nid = spec->autocfg.speaker_pins[nid];
2923 break;
2924 case SUBDEV_LINE_:
2925 nid = spec->autocfg.line_out_pins[nid];
2926 break;
2927 case SUBDEV_HP_:
2928 nid = spec->autocfg.hp_pins[nid];
2929 break;
2930 default:
2931 continue;
2932 }
2933 err = snd_hda_add_nid(codec, kctl, 0, nid);
2934 if (err < 0)
2935 return err;
2936 }
2937 u = knew->private_value;
2938 for (j = 0; j < 4; j++, u >>= 8) {
2939 nid = u & 0xff;
2940 if (nid == 0)
2941 continue;
2942 err = snd_hda_add_nid(codec, kctl, 0, nid);
2943 if (err < 0)
2944 return err;
2945 }
2946 }
2947 }
Takashi Iwaibae84e72010-03-22 08:30:20 +01002948
2949 alc_free_kctls(codec); /* no longer needed */
2950
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 return 0;
2952}
2953
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002954
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955/*
2956 * initialize the codec volumes, etc
2957 */
2958
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002959/*
2960 * generic initialization of ADC, input mixers and output mixers
2961 */
2962static struct hda_verb alc880_volume_init_verbs[] = {
2963 /*
2964 * Unmute ADC0-2 and set the default input to mic-in
2965 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002966 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002967 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002968 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002969 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002970 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002971 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002973 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2974 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002975 * Note: PASD motherboards uses the Line In 2 as the input for front
2976 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002978 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02002979 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2980 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2981 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2982 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2983 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2984 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2985 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002987 /*
2988 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002990 /* set vol=0 to output mixers */
2991 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2992 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2993 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2994 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2995 /* set up input amps for analog loopback */
2996 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002997 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2998 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002999 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3000 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02003001 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3002 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02003003 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3004 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005
3006 { }
3007};
3008
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003009/*
3010 * 3-stack pin configuration:
3011 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
3012 */
3013static struct hda_verb alc880_pin_3stack_init_verbs[] = {
3014 /*
3015 * preset connection lists of input pins
3016 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
3017 */
3018 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
3019 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3020 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
3021
3022 /*
3023 * Set pin mode and muting
3024 */
3025 /* set front pin widgets 0x14 for output */
3026 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3027 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3028 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3029 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3030 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3031 /* Mic2 (as headphone out) for HP output */
3032 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3033 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3034 /* Line In pin widget for input */
3035 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3036 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3037 /* Line2 (as front mic) pin widget for input and vref at 80% */
3038 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3039 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3040 /* CD pin widget for input */
3041 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3042
3043 { }
3044};
3045
3046/*
3047 * 5-stack pin configuration:
3048 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
3049 * line-in/side = 0x1a, f-mic = 0x1b
3050 */
3051static struct hda_verb alc880_pin_5stack_init_verbs[] = {
3052 /*
3053 * preset connection lists of input pins
3054 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
3055 */
3056 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3057 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
3058
3059 /*
3060 * Set pin mode and muting
3061 */
3062 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02003063 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3064 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3065 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3066 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003067 /* unmute pins for output (no gain on this amp) */
3068 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3069 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3070 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3071 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3072
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02003074 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003075 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3076 /* Mic2 (as headphone out) for HP output */
3077 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02003078 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003079 /* Line In pin widget for input */
3080 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3081 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3082 /* Line2 (as front mic) pin widget for input and vref at 80% */
3083 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3084 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3085 /* CD pin widget for input */
3086 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087
3088 { }
3089};
3090
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003091/*
3092 * W810 pin configuration:
3093 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
3094 */
3095static struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096 /* hphone/speaker input selector: front DAC */
3097 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
3098
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003099 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3100 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3101 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3102 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3103 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3104 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3105
3106 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02003107 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109 { }
3110};
3111
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003112/*
3113 * Z71V pin configuration:
3114 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
3115 */
3116static struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003117 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003118 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02003119 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003120 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02003121
Takashi Iwai16ded522005-06-10 19:58:24 +02003122 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003123 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02003124 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003125 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02003126
3127 { }
3128};
3129
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003130/*
3131 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003132 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
3133 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003134 */
3135static struct hda_verb alc880_pin_6stack_init_verbs[] = {
3136 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3137
Takashi Iwai16ded522005-06-10 19:58:24 +02003138 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003139 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003140 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003141 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003142 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003143 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003144 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003145 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3146
Takashi Iwai16ded522005-06-10 19:58:24 +02003147 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003148 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003149 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003150 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003151 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003152 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003153 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02003154 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003155 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02003156
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003157 { }
3158};
Takashi Iwai16ded522005-06-10 19:58:24 +02003159
Kailang Yangccc656c2006-10-17 12:32:26 +02003160/*
3161 * Uniwill pin configuration:
3162 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
3163 * line = 0x1a
3164 */
3165static struct hda_verb alc880_uniwill_init_verbs[] = {
3166 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3167
3168 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3169 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3170 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3171 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3172 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3173 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3174 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3175 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3176 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3177 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3178 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3179 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3180 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3181 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3182
3183 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3184 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3185 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3186 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3187 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3188 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3189 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
3190 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
3191 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3192
3193 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3194 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
3195
3196 { }
3197};
3198
3199/*
3200* Uniwill P53
Kailang Yangea1fb292008-08-26 12:58:38 +02003201* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
Kailang Yangccc656c2006-10-17 12:32:26 +02003202 */
3203static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
3204 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3205
3206 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3207 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3208 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3209 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3210 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3211 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3212 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3213 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3214 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3215 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3216 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3217 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3218
3219 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3220 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3221 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3222 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3223 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3224 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3225
3226 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3227 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
3228
3229 { }
3230};
3231
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003232static struct hda_verb alc880_beep_init_verbs[] = {
3233 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
3234 { }
3235};
3236
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003237/* auto-toggle front mic */
3238static void alc880_uniwill_mic_automute(struct hda_codec *codec)
3239{
3240 unsigned int present;
3241 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02003242
Wu Fengguang864f92b2009-11-18 12:38:02 +08003243 present = snd_hda_jack_detect(codec, 0x18);
Takashi Iwai47fd8302007-08-10 17:11:07 +02003244 bits = present ? HDA_AMP_MUTE : 0;
3245 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003246}
3247
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003248static void alc880_uniwill_setup(struct hda_codec *codec)
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003249{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003250 struct alc_spec *spec = codec->spec;
3251
3252 spec->autocfg.hp_pins[0] = 0x14;
3253 spec->autocfg.speaker_pins[0] = 0x15;
3254 spec->autocfg.speaker_pins[0] = 0x16;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003255}
3256
3257static void alc880_uniwill_init_hook(struct hda_codec *codec)
3258{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003259 alc_automute_amp(codec);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003260 alc880_uniwill_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02003261}
3262
3263static void alc880_uniwill_unsol_event(struct hda_codec *codec,
3264 unsigned int res)
3265{
3266 /* Looks like the unsol event is incompatible with the standard
3267 * definition. 4bit tag is placed at 28 bit!
3268 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003269 switch (res >> 28) {
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003270 case ALC880_MIC_EVENT:
3271 alc880_uniwill_mic_automute(codec);
3272 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003273 default:
3274 alc_automute_amp_unsol_event(codec, res);
3275 break;
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003276 }
Kailang Yangccc656c2006-10-17 12:32:26 +02003277}
3278
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003279static void alc880_uniwill_p53_setup(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02003280{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003281 struct alc_spec *spec = codec->spec;
Kailang Yangccc656c2006-10-17 12:32:26 +02003282
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003283 spec->autocfg.hp_pins[0] = 0x14;
3284 spec->autocfg.speaker_pins[0] = 0x15;
Kailang Yangccc656c2006-10-17 12:32:26 +02003285}
3286
3287static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
3288{
3289 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02003290
Kailang Yangccc656c2006-10-17 12:32:26 +02003291 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02003292 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
3293 present &= HDA_AMP_VOLMASK;
3294 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
3295 HDA_AMP_VOLMASK, present);
3296 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
3297 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02003298}
Takashi Iwai47fd8302007-08-10 17:11:07 +02003299
Kailang Yangccc656c2006-10-17 12:32:26 +02003300static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
3301 unsigned int res)
3302{
3303 /* Looks like the unsol event is incompatible with the standard
3304 * definition. 4bit tag is placed at 28 bit!
3305 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003306 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02003307 alc880_uniwill_p53_dcvol_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003308 else
3309 alc_automute_amp_unsol_event(codec, res);
Kailang Yangccc656c2006-10-17 12:32:26 +02003310}
3311
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003312/*
3313 * F1734 pin configuration:
3314 * HP = 0x14, speaker-out = 0x15, mic = 0x18
3315 */
3316static struct hda_verb alc880_pin_f1734_init_verbs[] = {
Michael Gruberee7a9c72008-03-10 11:30:59 +01003317 {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003318 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
3319 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
3320 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
3321 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
3322
3323 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3324 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3325 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3326 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3327
3328 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3329 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Michael Gruberee7a9c72008-03-10 11:30:59 +01003330 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003331 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3332 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3333 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3334 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3335 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3336 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02003337
Takashi Iwai937b4162008-02-11 14:52:36 +01003338 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
3339 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
3340
Takashi Iwai16ded522005-06-10 19:58:24 +02003341 { }
3342};
3343
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003344/*
3345 * ASUS pin configuration:
3346 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
3347 */
3348static struct hda_verb alc880_pin_asus_init_verbs[] = {
3349 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
3350 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
3351 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
3352 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
3353
3354 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3355 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3356 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3357 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3358 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3359 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3360 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3361 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3362
3363 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3364 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3365 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3366 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3367 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3368 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3369 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3370 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3371 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02003372
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003373 { }
3374};
3375
3376/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003377#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
3378#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
David Heidelberger64a8be72009-06-08 16:15:18 +02003379#define alc880_gpio3_init_verbs alc_gpio3_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003380
Kailang Yangdf694da2005-12-05 19:42:22 +01003381/* Clevo m520g init */
3382static struct hda_verb alc880_pin_clevo_init_verbs[] = {
3383 /* headphone output */
3384 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3385 /* line-out */
3386 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3387 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3388 /* Line-in */
3389 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3390 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3391 /* CD */
3392 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3393 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3394 /* Mic1 (rear panel) */
3395 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3396 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3397 /* Mic2 (front panel) */
3398 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3399 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3400 /* headphone */
3401 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3402 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3403 /* change to EAPD mode */
3404 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3405 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3406
3407 { }
3408};
3409
3410static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02003411 /* change to EAPD mode */
3412 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3413 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3414
Kailang Yangdf694da2005-12-05 19:42:22 +01003415 /* Headphone output */
3416 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3417 /* Front output*/
3418 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3419 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
3420
3421 /* Line In pin widget for input */
3422 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3423 /* CD pin widget for input */
3424 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3425 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3426 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3427
3428 /* change to EAPD mode */
3429 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3430 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
3431
3432 { }
3433};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003434
3435/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003436 * LG m1 express dual
3437 *
3438 * Pin assignment:
3439 * Rear Line-In/Out (blue): 0x14
3440 * Build-in Mic-In: 0x15
3441 * Speaker-out: 0x17
3442 * HP-Out (green): 0x1b
3443 * Mic-In/Out (red): 0x19
3444 * SPDIF-Out: 0x1e
3445 */
3446
3447/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
3448static hda_nid_t alc880_lg_dac_nids[3] = {
3449 0x05, 0x02, 0x03
3450};
3451
3452/* seems analog CD is not working */
3453static struct hda_input_mux alc880_lg_capture_source = {
3454 .num_items = 3,
3455 .items = {
3456 { "Mic", 0x1 },
3457 { "Line", 0x5 },
3458 { "Internal Mic", 0x6 },
3459 },
3460};
3461
3462/* 2,4,6 channel modes */
3463static struct hda_verb alc880_lg_ch2_init[] = {
3464 /* set line-in and mic-in to input */
3465 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
3466 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3467 { }
3468};
3469
3470static struct hda_verb alc880_lg_ch4_init[] = {
3471 /* set line-in to out and mic-in to input */
3472 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3473 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3474 { }
3475};
3476
3477static struct hda_verb alc880_lg_ch6_init[] = {
3478 /* set line-in and mic-in to output */
3479 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3480 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3481 { }
3482};
3483
3484static struct hda_channel_mode alc880_lg_ch_modes[3] = {
3485 { 2, alc880_lg_ch2_init },
3486 { 4, alc880_lg_ch4_init },
3487 { 6, alc880_lg_ch6_init },
3488};
3489
3490static struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003491 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
3492 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003493 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3494 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
3495 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
3496 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
3497 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
3498 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
3499 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3500 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
3501 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
3502 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
3503 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
3504 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
3505 {
3506 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3507 .name = "Channel Mode",
3508 .info = alc_ch_mode_info,
3509 .get = alc_ch_mode_get,
3510 .put = alc_ch_mode_put,
3511 },
3512 { } /* end */
3513};
3514
3515static struct hda_verb alc880_lg_init_verbs[] = {
3516 /* set capture source to mic-in */
3517 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3518 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3519 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3520 /* mute all amp mixer inputs */
3521 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02003522 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
3523 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003524 /* line-in to input */
3525 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3526 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3527 /* built-in mic */
3528 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3529 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3530 /* speaker-out */
3531 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3532 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3533 /* mic-in to input */
3534 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3535 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3536 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3537 /* HP-out */
3538 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
3539 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3540 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3541 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003542 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003543 { }
3544};
3545
3546/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003547static void alc880_lg_setup(struct hda_codec *codec)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003548{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003549 struct alc_spec *spec = codec->spec;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003550
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003551 spec->autocfg.hp_pins[0] = 0x1b;
3552 spec->autocfg.speaker_pins[0] = 0x17;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003553}
3554
3555/*
Takashi Iwaid6815182006-03-23 16:06:23 +01003556 * LG LW20
3557 *
3558 * Pin assignment:
3559 * Speaker-out: 0x14
3560 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003561 * Built-in Mic-In: 0x19
3562 * Line-In: 0x1b
3563 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01003564 * SPDIF-Out: 0x1e
3565 */
3566
Takashi Iwaid6815182006-03-23 16:06:23 +01003567static struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003568 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01003569 .items = {
3570 { "Mic", 0x0 },
3571 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003572 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003573 },
3574};
3575
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003576#define alc880_lg_lw_modes alc880_threestack_modes
3577
Takashi Iwaid6815182006-03-23 16:06:23 +01003578static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003579 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3580 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
3581 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
3582 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
3583 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
3584 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
3585 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
3586 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
3587 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
3588 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01003589 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3590 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3591 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
3592 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003593 {
3594 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3595 .name = "Channel Mode",
3596 .info = alc_ch_mode_info,
3597 .get = alc_ch_mode_get,
3598 .put = alc_ch_mode_put,
3599 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003600 { } /* end */
3601};
3602
3603static struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003604 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3605 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
3606 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
3607
Takashi Iwaid6815182006-03-23 16:06:23 +01003608 /* set capture source to mic-in */
3609 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3610 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3611 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02003612 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01003613 /* speaker-out */
3614 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3615 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3616 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01003617 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3618 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3619 /* mic-in to input */
3620 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3621 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3622 /* built-in mic */
3623 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3624 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3625 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003626 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaid6815182006-03-23 16:06:23 +01003627 { }
3628};
3629
3630/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003631static void alc880_lg_lw_setup(struct hda_codec *codec)
Takashi Iwaid6815182006-03-23 16:06:23 +01003632{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003633 struct alc_spec *spec = codec->spec;
Takashi Iwaid6815182006-03-23 16:06:23 +01003634
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003635 spec->autocfg.hp_pins[0] = 0x1b;
3636 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid6815182006-03-23 16:06:23 +01003637}
3638
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003639static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
3640 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3641 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
3642 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3643 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3644 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3645 HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
3646 { } /* end */
3647};
3648
3649static struct hda_input_mux alc880_medion_rim_capture_source = {
3650 .num_items = 2,
3651 .items = {
3652 { "Mic", 0x0 },
3653 { "Internal Mic", 0x1 },
3654 },
3655};
3656
3657static struct hda_verb alc880_medion_rim_init_verbs[] = {
3658 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3659
3660 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3661 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3662
3663 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3664 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3665 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3666 /* Mic2 (as headphone out) for HP output */
3667 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3668 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3669 /* Internal Speaker */
3670 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3671 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3672
3673 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3674 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3675
3676 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3677 { }
3678};
3679
3680/* toggle speaker-output according to the hp-jack state */
3681static void alc880_medion_rim_automute(struct hda_codec *codec)
3682{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003683 struct alc_spec *spec = codec->spec;
3684 alc_automute_amp(codec);
3685 /* toggle EAPD */
3686 if (spec->jack_present)
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003687 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
3688 else
3689 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
3690}
3691
3692static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
3693 unsigned int res)
3694{
3695 /* Looks like the unsol event is incompatible with the standard
3696 * definition. 4bit tag is placed at 28 bit!
3697 */
3698 if ((res >> 28) == ALC880_HP_EVENT)
3699 alc880_medion_rim_automute(codec);
3700}
3701
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003702static void alc880_medion_rim_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003703{
3704 struct alc_spec *spec = codec->spec;
3705
3706 spec->autocfg.hp_pins[0] = 0x14;
3707 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003708}
3709
Takashi Iwaicb53c622007-08-10 17:21:45 +02003710#ifdef CONFIG_SND_HDA_POWER_SAVE
3711static struct hda_amp_list alc880_loopbacks[] = {
3712 { 0x0b, HDA_INPUT, 0 },
3713 { 0x0b, HDA_INPUT, 1 },
3714 { 0x0b, HDA_INPUT, 2 },
3715 { 0x0b, HDA_INPUT, 3 },
3716 { 0x0b, HDA_INPUT, 4 },
3717 { } /* end */
3718};
3719
3720static struct hda_amp_list alc880_lg_loopbacks[] = {
3721 { 0x0b, HDA_INPUT, 1 },
3722 { 0x0b, HDA_INPUT, 6 },
3723 { 0x0b, HDA_INPUT, 7 },
3724 { } /* end */
3725};
3726#endif
3727
Takashi Iwaid6815182006-03-23 16:06:23 +01003728/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003729 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003730 */
Takashi Iwai16ded522005-06-10 19:58:24 +02003731
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732static int alc_init(struct hda_codec *codec)
3733{
3734 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003735 unsigned int i;
3736
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02003737 alc_fix_pll(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02003738 alc_auto_init_amp(codec, spec->init_amp);
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02003739
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003740 for (i = 0; i < spec->num_init_verbs; i++)
3741 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003742
3743 if (spec->init_hook)
3744 spec->init_hook(codec);
3745
Takashi Iwai9e5341b2010-09-21 09:57:06 +02003746 hda_call_check_power_status(codec, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003747 return 0;
3748}
3749
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003750static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
3751{
3752 struct alc_spec *spec = codec->spec;
3753
3754 if (spec->unsol_event)
3755 spec->unsol_event(codec, res);
3756}
3757
Takashi Iwaicb53c622007-08-10 17:21:45 +02003758#ifdef CONFIG_SND_HDA_POWER_SAVE
3759static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
3760{
3761 struct alc_spec *spec = codec->spec;
3762 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
3763}
3764#endif
3765
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766/*
3767 * Analog playback callbacks
3768 */
3769static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
3770 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003771 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772{
3773 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01003774 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
3775 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776}
3777
3778static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
3779 struct hda_codec *codec,
3780 unsigned int stream_tag,
3781 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003782 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783{
3784 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003785 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
3786 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787}
3788
3789static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3790 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003791 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792{
3793 struct alc_spec *spec = codec->spec;
3794 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
3795}
3796
3797/*
3798 * Digital out
3799 */
3800static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
3801 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003802 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803{
3804 struct alc_spec *spec = codec->spec;
3805 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
3806}
3807
Takashi Iwai6b97eb42007-04-05 14:51:48 +02003808static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
3809 struct hda_codec *codec,
3810 unsigned int stream_tag,
3811 unsigned int format,
3812 struct snd_pcm_substream *substream)
3813{
3814 struct alc_spec *spec = codec->spec;
3815 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
3816 stream_tag, format, substream);
3817}
3818
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01003819static int alc880_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3820 struct hda_codec *codec,
3821 struct snd_pcm_substream *substream)
3822{
3823 struct alc_spec *spec = codec->spec;
3824 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
3825}
3826
Linus Torvalds1da177e2005-04-16 15:20:36 -07003827static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
3828 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003829 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003830{
3831 struct alc_spec *spec = codec->spec;
3832 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
3833}
3834
3835/*
3836 * Analog capture
3837 */
Takashi Iwai63300792008-01-24 15:31:36 +01003838static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003839 struct hda_codec *codec,
3840 unsigned int stream_tag,
3841 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003842 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843{
3844 struct alc_spec *spec = codec->spec;
3845
Takashi Iwai63300792008-01-24 15:31:36 +01003846 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07003847 stream_tag, 0, format);
3848 return 0;
3849}
3850
Takashi Iwai63300792008-01-24 15:31:36 +01003851static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003853 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854{
3855 struct alc_spec *spec = codec->spec;
3856
Takashi Iwai888afa12008-03-18 09:57:50 +01003857 snd_hda_codec_cleanup_stream(codec,
3858 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003859 return 0;
3860}
3861
Takashi Iwai840b64c2010-07-13 22:49:01 +02003862/* analog capture with dynamic dual-adc changes */
3863static int dualmic_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
3864 struct hda_codec *codec,
3865 unsigned int stream_tag,
3866 unsigned int format,
3867 struct snd_pcm_substream *substream)
3868{
3869 struct alc_spec *spec = codec->spec;
3870 spec->cur_adc = spec->adc_nids[spec->cur_adc_idx];
3871 spec->cur_adc_stream_tag = stream_tag;
3872 spec->cur_adc_format = format;
3873 snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
3874 return 0;
3875}
3876
3877static int dualmic_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
3878 struct hda_codec *codec,
3879 struct snd_pcm_substream *substream)
3880{
3881 struct alc_spec *spec = codec->spec;
3882 snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
3883 spec->cur_adc = 0;
3884 return 0;
3885}
3886
3887static struct hda_pcm_stream dualmic_pcm_analog_capture = {
3888 .substreams = 1,
3889 .channels_min = 2,
3890 .channels_max = 2,
3891 .nid = 0, /* fill later */
3892 .ops = {
3893 .prepare = dualmic_capture_pcm_prepare,
3894 .cleanup = dualmic_capture_pcm_cleanup
3895 },
3896};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897
3898/*
3899 */
3900static struct hda_pcm_stream alc880_pcm_analog_playback = {
3901 .substreams = 1,
3902 .channels_min = 2,
3903 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003904 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905 .ops = {
3906 .open = alc880_playback_pcm_open,
3907 .prepare = alc880_playback_pcm_prepare,
3908 .cleanup = alc880_playback_pcm_cleanup
3909 },
3910};
3911
3912static struct hda_pcm_stream alc880_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01003913 .substreams = 1,
3914 .channels_min = 2,
3915 .channels_max = 2,
3916 /* NID is set in alc_build_pcms */
3917};
3918
3919static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
3920 .substreams = 1,
3921 .channels_min = 2,
3922 .channels_max = 2,
3923 /* NID is set in alc_build_pcms */
3924};
3925
3926static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
3927 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928 .channels_min = 2,
3929 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003930 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931 .ops = {
Takashi Iwai63300792008-01-24 15:31:36 +01003932 .prepare = alc880_alt_capture_pcm_prepare,
3933 .cleanup = alc880_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934 },
3935};
3936
3937static struct hda_pcm_stream alc880_pcm_digital_playback = {
3938 .substreams = 1,
3939 .channels_min = 2,
3940 .channels_max = 2,
3941 /* NID is set in alc_build_pcms */
3942 .ops = {
3943 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02003944 .close = alc880_dig_playback_pcm_close,
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01003945 .prepare = alc880_dig_playback_pcm_prepare,
3946 .cleanup = alc880_dig_playback_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07003947 },
3948};
3949
3950static struct hda_pcm_stream alc880_pcm_digital_capture = {
3951 .substreams = 1,
3952 .channels_min = 2,
3953 .channels_max = 2,
3954 /* NID is set in alc_build_pcms */
3955};
3956
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003957/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwai63300792008-01-24 15:31:36 +01003958static struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003959 .substreams = 0,
3960 .channels_min = 0,
3961 .channels_max = 0,
3962};
3963
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964static int alc_build_pcms(struct hda_codec *codec)
3965{
3966 struct alc_spec *spec = codec->spec;
3967 struct hda_pcm *info = spec->pcm_rec;
3968 int i;
3969
3970 codec->num_pcms = 1;
3971 codec->pcm_info = info;
3972
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003973 if (spec->no_analog)
3974 goto skip_analog;
3975
Takashi Iwai812a2cc2009-05-16 10:00:49 +02003976 snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog),
3977 "%s Analog", codec->chip_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978 info->name = spec->stream_name_analog;
Kailang Yang274693f2009-12-03 10:07:50 +01003979
Takashi Iwai4a471b72005-12-07 13:56:29 +01003980 if (spec->stream_analog_playback) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02003981 if (snd_BUG_ON(!spec->multiout.dac_nids))
3982 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003983 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
3984 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
3985 }
3986 if (spec->stream_analog_capture) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02003987 if (snd_BUG_ON(!spec->adc_nids))
3988 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003989 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
3990 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
3991 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992
Takashi Iwai4a471b72005-12-07 13:56:29 +01003993 if (spec->channel_mode) {
3994 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
3995 for (i = 0; i < spec->num_channel_mode; i++) {
3996 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
3997 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
3998 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999 }
4000 }
4001
Takashi Iwaie64f14f2009-01-20 18:32:55 +01004002 skip_analog:
Takashi Iwaie08a0072006-09-07 17:52:14 +02004003 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwai812a2cc2009-05-16 10:00:49 +02004005 snprintf(spec->stream_name_digital,
4006 sizeof(spec->stream_name_digital),
4007 "%s Digital", codec->chip_name);
Takashi Iwaie08a0072006-09-07 17:52:14 +02004008 codec->num_pcms = 2;
Wu Fengguangb25c9da2009-02-06 15:02:27 +08004009 codec->slave_dig_outs = spec->multiout.slave_dig_outs;
Takashi Iwaic06134d2006-10-11 18:49:13 +02004010 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011 info->name = spec->stream_name_digital;
Takashi Iwai8c441982009-01-20 18:30:20 +01004012 if (spec->dig_out_type)
4013 info->pcm_type = spec->dig_out_type;
4014 else
4015 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004016 if (spec->multiout.dig_out_nid &&
4017 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
4019 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
4020 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01004021 if (spec->dig_in_nid &&
4022 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
4024 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
4025 }
Takashi Iwai963f8032008-08-11 10:04:40 +02004026 /* FIXME: do we need this for all Realtek codec models? */
4027 codec->spdif_status_reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028 }
4029
Takashi Iwaie64f14f2009-01-20 18:32:55 +01004030 if (spec->no_analog)
4031 return 0;
4032
Takashi Iwaie08a0072006-09-07 17:52:14 +02004033 /* If the use of more than one ADC is requested for the current
4034 * model, configure a second analog capture-only PCM.
4035 */
4036 /* Additional Analaog capture for index #2 */
Takashi Iwai63300792008-01-24 15:31:36 +01004037 if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
4038 (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02004039 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02004040 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02004041 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01004042 if (spec->alt_dac_nid) {
4043 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
4044 *spec->stream_analog_alt_playback;
4045 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
4046 spec->alt_dac_nid;
4047 } else {
4048 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
4049 alc_pcm_null_stream;
4050 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
4051 }
4052 if (spec->num_adc_nids > 1) {
4053 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
4054 *spec->stream_analog_alt_capture;
4055 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
4056 spec->adc_nids[1];
4057 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
4058 spec->num_adc_nids - 1;
4059 } else {
4060 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
4061 alc_pcm_null_stream;
4062 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02004063 }
4064 }
4065
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066 return 0;
4067}
4068
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004069static inline void alc_shutup(struct hda_codec *codec)
4070{
4071 snd_hda_shutup_pins(codec);
4072}
4073
Takashi Iwai603c4012008-07-30 15:01:44 +02004074static void alc_free_kctls(struct hda_codec *codec)
4075{
4076 struct alc_spec *spec = codec->spec;
4077
4078 if (spec->kctls.list) {
4079 struct snd_kcontrol_new *kctl = spec->kctls.list;
4080 int i;
4081 for (i = 0; i < spec->kctls.used; i++)
4082 kfree(kctl[i].name);
4083 }
4084 snd_array_free(&spec->kctls);
4085}
4086
Linus Torvalds1da177e2005-04-16 15:20:36 -07004087static void alc_free(struct hda_codec *codec)
4088{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004089 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004090
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004091 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004092 return;
4093
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004094 alc_shutup(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +02004095 alc_free_kctls(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004096 kfree(spec);
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09004097 snd_hda_detach_beep_device(codec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004098}
4099
Hector Martinf5de24b2009-12-20 22:51:31 +01004100#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -05004101static void alc_power_eapd(struct hda_codec *codec)
4102{
4103 /* We currently only handle front, HP */
4104 switch (codec->vendor_id) {
4105 case 0x10ec0260:
Takashi Iwai9e4c8492010-01-19 15:53:43 +01004106 set_eapd(codec, 0x0f, 0);
4107 set_eapd(codec, 0x10, 0);
Daniel T Chenc97259d2009-12-27 18:52:08 -05004108 break;
4109 case 0x10ec0262:
4110 case 0x10ec0267:
4111 case 0x10ec0268:
4112 case 0x10ec0269:
Takashi Iwai9e4c8492010-01-19 15:53:43 +01004113 case 0x10ec0270:
Daniel T Chenc97259d2009-12-27 18:52:08 -05004114 case 0x10ec0272:
4115 case 0x10ec0660:
4116 case 0x10ec0662:
4117 case 0x10ec0663:
4118 case 0x10ec0862:
4119 case 0x10ec0889:
Takashi Iwai9e4c8492010-01-19 15:53:43 +01004120 set_eapd(codec, 0x14, 0);
4121 set_eapd(codec, 0x15, 0);
Daniel T Chenc97259d2009-12-27 18:52:08 -05004122 break;
4123 }
4124}
4125
Hector Martinf5de24b2009-12-20 22:51:31 +01004126static int alc_suspend(struct hda_codec *codec, pm_message_t state)
4127{
4128 struct alc_spec *spec = codec->spec;
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004129 alc_shutup(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01004130 if (spec && spec->power_hook)
Daniel T Chenc97259d2009-12-27 18:52:08 -05004131 spec->power_hook(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01004132 return 0;
4133}
4134#endif
4135
Takashi Iwaie044c392008-10-27 16:56:24 +01004136#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaie044c392008-10-27 16:56:24 +01004137static int alc_resume(struct hda_codec *codec)
4138{
Takashi Iwaie044c392008-10-27 16:56:24 +01004139 codec->patch_ops.init(codec);
4140 snd_hda_codec_resume_amp(codec);
4141 snd_hda_codec_resume_cache(codec);
Takashi Iwai9e5341b2010-09-21 09:57:06 +02004142 hda_call_check_power_status(codec, 0x01);
Takashi Iwaie044c392008-10-27 16:56:24 +01004143 return 0;
4144}
Takashi Iwaie044c392008-10-27 16:56:24 +01004145#endif
4146
Linus Torvalds1da177e2005-04-16 15:20:36 -07004147/*
4148 */
4149static struct hda_codec_ops alc_patch_ops = {
4150 .build_controls = alc_build_controls,
4151 .build_pcms = alc_build_pcms,
4152 .init = alc_init,
4153 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004154 .unsol_event = alc_unsol_event,
Takashi Iwaie044c392008-10-27 16:56:24 +01004155#ifdef SND_HDA_NEEDS_RESUME
4156 .resume = alc_resume,
4157#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02004158#ifdef CONFIG_SND_HDA_POWER_SAVE
Hector Martinf5de24b2009-12-20 22:51:31 +01004159 .suspend = alc_suspend,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004160 .check_power_status = alc_check_power_status,
4161#endif
Daniel T Chenc97259d2009-12-27 18:52:08 -05004162 .reboot_notify = alc_shutup,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163};
4164
Kailang Yangc027ddc2010-03-19 11:33:06 +01004165/* replace the codec chip_name with the given string */
4166static int alc_codec_rename(struct hda_codec *codec, const char *name)
4167{
4168 kfree(codec->chip_name);
4169 codec->chip_name = kstrdup(name, GFP_KERNEL);
4170 if (!codec->chip_name) {
4171 alc_free(codec);
4172 return -ENOMEM;
4173 }
4174 return 0;
4175}
4176
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004177/*
4178 * Test configuration for debugging
4179 *
4180 * Almost all inputs/outputs are enabled. I/O pins can be configured via
4181 * enum controls.
4182 */
4183#ifdef CONFIG_SND_DEBUG
4184static hda_nid_t alc880_test_dac_nids[4] = {
4185 0x02, 0x03, 0x04, 0x05
4186};
4187
4188static struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004189 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004190 .items = {
4191 { "In-1", 0x0 },
4192 { "In-2", 0x1 },
4193 { "In-3", 0x2 },
4194 { "In-4", 0x3 },
4195 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004196 { "Front", 0x5 },
4197 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004198 },
4199};
4200
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01004201static struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004202 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02004203 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004204 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02004205 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004206};
4207
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004208static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
4209 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004210{
4211 static char *texts[] = {
4212 "N/A", "Line Out", "HP Out",
4213 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
4214 };
4215 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
4216 uinfo->count = 1;
4217 uinfo->value.enumerated.items = 8;
4218 if (uinfo->value.enumerated.item >= 8)
4219 uinfo->value.enumerated.item = 7;
4220 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
4221 return 0;
4222}
4223
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004224static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
4225 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004226{
4227 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4228 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4229 unsigned int pin_ctl, item = 0;
4230
4231 pin_ctl = snd_hda_codec_read(codec, nid, 0,
4232 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
4233 if (pin_ctl & AC_PINCTL_OUT_EN) {
4234 if (pin_ctl & AC_PINCTL_HP_EN)
4235 item = 2;
4236 else
4237 item = 1;
4238 } else if (pin_ctl & AC_PINCTL_IN_EN) {
4239 switch (pin_ctl & AC_PINCTL_VREFEN) {
4240 case AC_PINCTL_VREF_HIZ: item = 3; break;
4241 case AC_PINCTL_VREF_50: item = 4; break;
4242 case AC_PINCTL_VREF_GRD: item = 5; break;
4243 case AC_PINCTL_VREF_80: item = 6; break;
4244 case AC_PINCTL_VREF_100: item = 7; break;
4245 }
4246 }
4247 ucontrol->value.enumerated.item[0] = item;
4248 return 0;
4249}
4250
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004251static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
4252 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004253{
4254 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4255 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4256 static unsigned int ctls[] = {
4257 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
4258 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
4259 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
4260 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
4261 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
4262 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
4263 };
4264 unsigned int old_ctl, new_ctl;
4265
4266 old_ctl = snd_hda_codec_read(codec, nid, 0,
4267 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
4268 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
4269 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004270 int val;
4271 snd_hda_codec_write_cache(codec, nid, 0,
4272 AC_VERB_SET_PIN_WIDGET_CONTROL,
4273 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02004274 val = ucontrol->value.enumerated.item[0] >= 3 ?
4275 HDA_AMP_MUTE : 0;
4276 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
4277 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004278 return 1;
4279 }
4280 return 0;
4281}
4282
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004283static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
4284 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004285{
4286 static char *texts[] = {
4287 "Front", "Surround", "CLFE", "Side"
4288 };
4289 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
4290 uinfo->count = 1;
4291 uinfo->value.enumerated.items = 4;
4292 if (uinfo->value.enumerated.item >= 4)
4293 uinfo->value.enumerated.item = 3;
4294 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
4295 return 0;
4296}
4297
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004298static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
4299 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004300{
4301 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4302 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4303 unsigned int sel;
4304
4305 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
4306 ucontrol->value.enumerated.item[0] = sel & 3;
4307 return 0;
4308}
4309
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004310static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
4311 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004312{
4313 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4314 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4315 unsigned int sel;
4316
4317 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
4318 if (ucontrol->value.enumerated.item[0] != sel) {
4319 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004320 snd_hda_codec_write_cache(codec, nid, 0,
4321 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004322 return 1;
4323 }
4324 return 0;
4325}
4326
4327#define PIN_CTL_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_ctl_info, \
4332 .get = alc_test_pin_ctl_get, \
4333 .put = alc_test_pin_ctl_put, \
4334 .private_value = nid \
4335 }
4336
4337#define PIN_SRC_TEST(xname,nid) { \
4338 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
4339 .name = xname, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01004340 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004341 .info = alc_test_pin_src_info, \
4342 .get = alc_test_pin_src_get, \
4343 .put = alc_test_pin_src_put, \
4344 .private_value = nid \
4345 }
4346
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004347static struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02004348 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
4349 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
4350 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
4351 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004352 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
4353 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
4354 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
4355 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004356 PIN_CTL_TEST("Front Pin Mode", 0x14),
4357 PIN_CTL_TEST("Surround Pin Mode", 0x15),
4358 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
4359 PIN_CTL_TEST("Side Pin Mode", 0x17),
4360 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
4361 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
4362 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
4363 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
4364 PIN_SRC_TEST("In-1 Pin Source", 0x18),
4365 PIN_SRC_TEST("In-2 Pin Source", 0x19),
4366 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
4367 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
4368 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
4369 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
4370 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
4371 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
4372 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
4373 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
4374 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
4375 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
4376 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
4377 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004378 {
4379 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4380 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01004381 .info = alc_ch_mode_info,
4382 .get = alc_ch_mode_get,
4383 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004384 },
4385 { } /* end */
4386};
4387
4388static struct hda_verb alc880_test_init_verbs[] = {
4389 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02004390 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4391 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4392 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4393 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4394 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4395 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4396 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4397 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004398 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02004399 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4400 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4401 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4402 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004403 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004404 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4405 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4406 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4407 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004408 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004409 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4410 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4411 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4412 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004413 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02004414 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4415 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02004416 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4417 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4418 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004419 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02004420 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4421 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4422 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4423 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004424 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02004425 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004426 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004427 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004428 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004429 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004430 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004431 /* Analog input/passthru */
4432 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4433 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4434 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4435 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4436 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004437 { }
4438};
4439#endif
4440
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441/*
4442 */
4443
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004444static const char *alc880_models[ALC880_MODEL_LAST] = {
4445 [ALC880_3ST] = "3stack",
4446 [ALC880_TCL_S700] = "tcl",
4447 [ALC880_3ST_DIG] = "3stack-digout",
4448 [ALC880_CLEVO] = "clevo",
4449 [ALC880_5ST] = "5stack",
4450 [ALC880_5ST_DIG] = "5stack-digout",
4451 [ALC880_W810] = "w810",
4452 [ALC880_Z71V] = "z71v",
4453 [ALC880_6ST] = "6stack",
4454 [ALC880_6ST_DIG] = "6stack-digout",
4455 [ALC880_ASUS] = "asus",
4456 [ALC880_ASUS_W1V] = "asus-w1v",
4457 [ALC880_ASUS_DIG] = "asus-dig",
4458 [ALC880_ASUS_DIG2] = "asus-dig2",
4459 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004460 [ALC880_UNIWILL_P53] = "uniwill-p53",
4461 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004462 [ALC880_F1734] = "F1734",
4463 [ALC880_LG] = "lg",
4464 [ALC880_LG_LW] = "lg-lw",
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004465 [ALC880_MEDION_RIM] = "medion",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004466#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004467 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004468#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004469 [ALC880_AUTO] = "auto",
4470};
4471
4472static struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004473 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004474 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
4475 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
4476 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
4477 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
4478 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
4479 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
4480 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
4481 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004482 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
4483 SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004484 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
4485 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
4486 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
4487 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
4488 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
4489 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
4490 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
4491 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
4492 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
4493 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Travis Place186c3112008-05-20 11:54:41 +02004494 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004495 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
4496 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
4497 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004498 SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004499 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004500 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
4501 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004502 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
4503 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004504 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
4505 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
4506 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
4507 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004508 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
4509 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004510 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004511 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004512 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004513 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004514 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
4515 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004516 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004517 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004518 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004519 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004520 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Travis Place1d116042008-06-23 11:42:30 +02004521 SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
Daniel T Chen33535412010-04-22 07:15:26 -04004522 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_F1734),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004523 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004524 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004525 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
4526 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004527 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004528 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
4529 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
4530 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
4531 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004532 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
4533 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004534 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004535 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004536 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
4537 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004538 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
4539 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
4540 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004541 /* default Intel */
4542 SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004543 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
4544 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004545 {}
4546};
4547
Takashi Iwai16ded522005-06-10 19:58:24 +02004548/*
Kailang Yangdf694da2005-12-05 19:42:22 +01004549 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02004550 */
Takashi Iwai16ded522005-06-10 19:58:24 +02004551static struct alc_config_preset alc880_presets[] = {
4552 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004553 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004554 .init_verbs = { alc880_volume_init_verbs,
4555 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004556 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02004557 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004558 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4559 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004560 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004561 .input_mux = &alc880_capture_source,
4562 },
4563 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004564 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004565 .init_verbs = { alc880_volume_init_verbs,
4566 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004567 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02004568 .dac_nids = alc880_dac_nids,
4569 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004570 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4571 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004572 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004573 .input_mux = &alc880_capture_source,
4574 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004575 [ALC880_TCL_S700] = {
4576 .mixers = { alc880_tcl_s700_mixer },
4577 .init_verbs = { alc880_volume_init_verbs,
4578 alc880_pin_tcl_S700_init_verbs,
4579 alc880_gpio2_init_verbs },
4580 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4581 .dac_nids = alc880_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004582 .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */
4583 .num_adc_nids = 1, /* single ADC */
Kailang Yangdf694da2005-12-05 19:42:22 +01004584 .hp_nid = 0x03,
4585 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4586 .channel_mode = alc880_2_jack_modes,
4587 .input_mux = &alc880_capture_source,
4588 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004589 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004590 .mixers = { alc880_three_stack_mixer,
4591 alc880_five_stack_mixer},
4592 .init_verbs = { alc880_volume_init_verbs,
4593 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004594 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4595 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004596 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
4597 .channel_mode = alc880_fivestack_modes,
4598 .input_mux = &alc880_capture_source,
4599 },
4600 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004601 .mixers = { alc880_three_stack_mixer,
4602 alc880_five_stack_mixer },
4603 .init_verbs = { alc880_volume_init_verbs,
4604 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004605 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4606 .dac_nids = alc880_dac_nids,
4607 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004608 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
4609 .channel_mode = alc880_fivestack_modes,
4610 .input_mux = &alc880_capture_source,
4611 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02004612 [ALC880_6ST] = {
4613 .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 Iwaib6482d42005-06-27 15:32:43 +02004616 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
4617 .dac_nids = alc880_6st_dac_nids,
4618 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
4619 .channel_mode = alc880_sixstack_modes,
4620 .input_mux = &alc880_6stack_capture_source,
4621 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004622 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004623 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004624 .init_verbs = { alc880_volume_init_verbs,
4625 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004626 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
4627 .dac_nids = alc880_6st_dac_nids,
4628 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004629 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
4630 .channel_mode = alc880_sixstack_modes,
4631 .input_mux = &alc880_6stack_capture_source,
4632 },
4633 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004634 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004635 .init_verbs = { alc880_volume_init_verbs,
4636 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02004637 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004638 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
4639 .dac_nids = alc880_w810_dac_nids,
4640 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004641 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
4642 .channel_mode = alc880_w810_modes,
4643 .input_mux = &alc880_capture_source,
4644 },
4645 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004646 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004647 .init_verbs = { alc880_volume_init_verbs,
4648 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004649 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
4650 .dac_nids = alc880_z71v_dac_nids,
4651 .dig_out_nid = ALC880_DIGOUT_NID,
4652 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004653 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4654 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02004655 .input_mux = &alc880_capture_source,
4656 },
4657 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004658 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004659 .init_verbs = { alc880_volume_init_verbs,
4660 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004661 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
4662 .dac_nids = alc880_f1734_dac_nids,
4663 .hp_nid = 0x02,
4664 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4665 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01004666 .input_mux = &alc880_f1734_capture_source,
4667 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004668 .setup = alc880_uniwill_p53_setup,
4669 .init_hook = alc_automute_amp,
Takashi Iwai16ded522005-06-10 19:58:24 +02004670 },
4671 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004672 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004673 .init_verbs = { alc880_volume_init_verbs,
4674 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004675 alc880_gpio1_init_verbs },
4676 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4677 .dac_nids = alc880_asus_dac_nids,
4678 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4679 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004680 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004681 .input_mux = &alc880_capture_source,
4682 },
4683 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004684 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004685 .init_verbs = { alc880_volume_init_verbs,
4686 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004687 alc880_gpio1_init_verbs },
4688 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4689 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004690 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004691 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4692 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004693 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004694 .input_mux = &alc880_capture_source,
4695 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004696 [ALC880_ASUS_DIG2] = {
4697 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004698 .init_verbs = { alc880_volume_init_verbs,
4699 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01004700 alc880_gpio2_init_verbs }, /* use GPIO2 */
4701 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4702 .dac_nids = alc880_asus_dac_nids,
4703 .dig_out_nid = ALC880_DIGOUT_NID,
4704 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4705 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004706 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01004707 .input_mux = &alc880_capture_source,
4708 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004709 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004710 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004711 .init_verbs = { alc880_volume_init_verbs,
4712 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004713 alc880_gpio1_init_verbs },
4714 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4715 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004716 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004717 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4718 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004719 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004720 .input_mux = &alc880_capture_source,
4721 },
4722 [ALC880_UNIWILL_DIG] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004723 .mixers = { alc880_asus_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02004724 .init_verbs = { alc880_volume_init_verbs,
4725 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004726 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4727 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004728 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004729 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4730 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004731 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004732 .input_mux = &alc880_capture_source,
4733 },
Kailang Yangccc656c2006-10-17 12:32:26 +02004734 [ALC880_UNIWILL] = {
4735 .mixers = { alc880_uniwill_mixer },
4736 .init_verbs = { alc880_volume_init_verbs,
4737 alc880_uniwill_init_verbs },
4738 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4739 .dac_nids = alc880_asus_dac_nids,
4740 .dig_out_nid = ALC880_DIGOUT_NID,
4741 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4742 .channel_mode = alc880_threestack_modes,
4743 .need_dac_fix = 1,
4744 .input_mux = &alc880_capture_source,
4745 .unsol_event = alc880_uniwill_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004746 .setup = alc880_uniwill_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004747 .init_hook = alc880_uniwill_init_hook,
Kailang Yangccc656c2006-10-17 12:32:26 +02004748 },
4749 [ALC880_UNIWILL_P53] = {
4750 .mixers = { alc880_uniwill_p53_mixer },
4751 .init_verbs = { alc880_volume_init_verbs,
4752 alc880_uniwill_p53_init_verbs },
4753 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4754 .dac_nids = alc880_asus_dac_nids,
4755 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004756 .channel_mode = alc880_threestack_modes,
4757 .input_mux = &alc880_capture_source,
4758 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004759 .setup = alc880_uniwill_p53_setup,
4760 .init_hook = alc_automute_amp,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004761 },
4762 [ALC880_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004763 .mixers = { alc880_fujitsu_mixer },
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004764 .init_verbs = { alc880_volume_init_verbs,
4765 alc880_uniwill_p53_init_verbs,
4766 alc880_beep_init_verbs },
4767 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4768 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02004769 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004770 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4771 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02004772 .input_mux = &alc880_capture_source,
4773 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004774 .setup = alc880_uniwill_p53_setup,
4775 .init_hook = alc_automute_amp,
Kailang Yangccc656c2006-10-17 12:32:26 +02004776 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004777 [ALC880_CLEVO] = {
4778 .mixers = { alc880_three_stack_mixer },
4779 .init_verbs = { alc880_volume_init_verbs,
4780 alc880_pin_clevo_init_verbs },
4781 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4782 .dac_nids = alc880_dac_nids,
4783 .hp_nid = 0x03,
4784 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4785 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004786 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01004787 .input_mux = &alc880_capture_source,
4788 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004789 [ALC880_LG] = {
4790 .mixers = { alc880_lg_mixer },
4791 .init_verbs = { alc880_volume_init_verbs,
4792 alc880_lg_init_verbs },
4793 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
4794 .dac_nids = alc880_lg_dac_nids,
4795 .dig_out_nid = ALC880_DIGOUT_NID,
4796 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
4797 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004798 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004799 .input_mux = &alc880_lg_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004800 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004801 .setup = alc880_lg_setup,
4802 .init_hook = alc_automute_amp,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004803#ifdef CONFIG_SND_HDA_POWER_SAVE
4804 .loopbacks = alc880_lg_loopbacks,
4805#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004806 },
Takashi Iwaid6815182006-03-23 16:06:23 +01004807 [ALC880_LG_LW] = {
4808 .mixers = { alc880_lg_lw_mixer },
4809 .init_verbs = { alc880_volume_init_verbs,
4810 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004811 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01004812 .dac_nids = alc880_dac_nids,
4813 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004814 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
4815 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01004816 .input_mux = &alc880_lg_lw_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004817 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004818 .setup = alc880_lg_lw_setup,
4819 .init_hook = alc_automute_amp,
Takashi Iwaid6815182006-03-23 16:06:23 +01004820 },
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004821 [ALC880_MEDION_RIM] = {
4822 .mixers = { alc880_medion_rim_mixer },
4823 .init_verbs = { alc880_volume_init_verbs,
4824 alc880_medion_rim_init_verbs,
4825 alc_gpio2_init_verbs },
4826 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4827 .dac_nids = alc880_dac_nids,
4828 .dig_out_nid = ALC880_DIGOUT_NID,
4829 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4830 .channel_mode = alc880_2_jack_modes,
4831 .input_mux = &alc880_medion_rim_capture_source,
4832 .unsol_event = alc880_medion_rim_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004833 .setup = alc880_medion_rim_setup,
4834 .init_hook = alc880_medion_rim_automute,
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004835 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004836#ifdef CONFIG_SND_DEBUG
4837 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004838 .mixers = { alc880_test_mixer },
4839 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004840 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
4841 .dac_nids = alc880_test_dac_nids,
4842 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004843 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
4844 .channel_mode = alc880_test_modes,
4845 .input_mux = &alc880_test_capture_source,
4846 },
4847#endif
4848};
4849
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004850/*
4851 * Automatic parse of I/O pins from the BIOS configuration
4852 */
4853
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004854enum {
4855 ALC_CTL_WIDGET_VOL,
4856 ALC_CTL_WIDGET_MUTE,
4857 ALC_CTL_BIND_MUTE,
4858};
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004859static struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004860 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
4861 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01004862 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004863};
4864
4865/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004866static int add_control(struct alc_spec *spec, int type, const char *name,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02004867 int cidx, unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004868{
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004869 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004870
Takashi Iwai603c4012008-07-30 15:01:44 +02004871 snd_array_init(&spec->kctls, sizeof(*knew), 32);
4872 knew = snd_array_new(&spec->kctls);
4873 if (!knew)
4874 return -ENOMEM;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004875 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07004876 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004877 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004878 return -ENOMEM;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02004879 knew->index = cidx;
Jaroslav Kysela4d02d1b2009-11-12 10:15:48 +01004880 if (get_amp_nid_(val))
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01004881 knew->subdevice = HDA_SUBDEV_AMP_FLAG;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004882 knew->private_value = val;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004883 return 0;
4884}
4885
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004886static int add_control_with_pfx(struct alc_spec *spec, int type,
4887 const char *pfx, const char *dir,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02004888 const char *sfx, int cidx, unsigned long val)
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004889{
4890 char name[32];
4891 snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
Takashi Iwai66ceeb62010-08-30 13:05:52 +02004892 return add_control(spec, type, name, cidx, val);
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004893}
4894
Takashi Iwai66ceeb62010-08-30 13:05:52 +02004895#define add_pb_vol_ctrl(spec, type, pfx, val) \
4896 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
4897#define add_pb_sw_ctrl(spec, type, pfx, val) \
4898 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
4899#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \
4900 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
4901#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \
4902 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004903
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004904#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
4905#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
4906#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
4907#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004908#define alc880_idx_to_dac(nid) ((nid) + 0x02)
4909#define alc880_dac_to_idx(nid) ((nid) - 0x02)
4910#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
4911#define alc880_idx_to_selector(nid) ((nid) + 0x10)
4912#define ALC880_PIN_CD_NID 0x1c
4913
4914/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004915static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
4916 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004917{
4918 hda_nid_t nid;
4919 int assigned[4];
4920 int i, j;
4921
4922 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02004923 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004924
4925 /* check the pins hardwired to audio widget */
4926 for (i = 0; i < cfg->line_outs; i++) {
4927 nid = cfg->line_out_pins[i];
4928 if (alc880_is_fixed_pin(nid)) {
4929 int idx = alc880_fixed_pin_idx(nid);
Libin Yang5014f192005-11-23 15:48:36 +01004930 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004931 assigned[idx] = 1;
4932 }
4933 }
4934 /* left pins can be connect to any audio widget */
4935 for (i = 0; i < cfg->line_outs; i++) {
4936 nid = cfg->line_out_pins[i];
4937 if (alc880_is_fixed_pin(nid))
4938 continue;
4939 /* search for an empty channel */
4940 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004941 if (!assigned[j]) {
4942 spec->multiout.dac_nids[i] =
4943 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004944 assigned[j] = 1;
4945 break;
4946 }
4947 }
4948 }
4949 spec->multiout.num_dacs = cfg->line_outs;
4950 return 0;
4951}
4952
4953/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01004954static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
4955 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004956{
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004957 static const char *chname[4] = {
4958 "Front", "Surround", NULL /*CLFE*/, "Side"
4959 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004960 hda_nid_t nid;
4961 int i, err;
4962
4963 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004964 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004965 continue;
4966 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
4967 if (i == 2) {
4968 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004969 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
4970 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004971 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
4972 HDA_OUTPUT));
4973 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004974 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004975 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
4976 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004977 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
4978 HDA_OUTPUT));
4979 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004980 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004981 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
4982 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004983 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
4984 HDA_INPUT));
4985 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004986 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004987 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
4988 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004989 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
4990 HDA_INPUT));
4991 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004992 return err;
4993 } else {
Takashi Iwaicb162b62009-08-25 16:05:03 +02004994 const char *pfx;
4995 if (cfg->line_outs == 1 &&
4996 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
4997 pfx = "Speaker";
4998 else
4999 pfx = chname[i];
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005000 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005001 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
5002 HDA_OUTPUT));
5003 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005004 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005005 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005006 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
5007 HDA_INPUT));
5008 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005009 return err;
5010 }
5011 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005012 return 0;
5013}
5014
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005015/* add playback controls for speaker and HP outputs */
5016static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
5017 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005018{
5019 hda_nid_t nid;
5020 int err;
5021
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005022 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005023 return 0;
5024
5025 if (alc880_is_fixed_pin(pin)) {
5026 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01005027 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005028 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005029 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01005030 else
5031 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005032 /* control HP volume/switch on the output mixer amp */
5033 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005034 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005035 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
5036 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005037 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005038 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005039 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
5040 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005041 return err;
5042 } else if (alc880_is_multi_pin(pin)) {
5043 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005044 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005045 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005046 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
5047 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005048 return err;
5049 }
5050 return 0;
5051}
5052
5053/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005054static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005055 const char *ctlname, int ctlidx,
Kailang Yangdf694da2005-12-05 19:42:22 +01005056 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005057{
Kailang Yangdf694da2005-12-05 19:42:22 +01005058 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005059
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005060 err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, ctlidx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005061 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
5062 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005063 return err;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005064 err = __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, ctlidx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005065 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
5066 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005067 return err;
5068 return 0;
5069}
5070
Takashi Iwai05f5f472009-08-25 13:10:18 +02005071static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005072{
Takashi Iwai05f5f472009-08-25 13:10:18 +02005073 unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
5074 return (pincap & AC_PINCAP_IN) != 0;
5075}
5076
5077/* create playback/capture controls for input pins */
5078static int alc_auto_create_input_ctls(struct hda_codec *codec,
5079 const struct auto_pin_cfg *cfg,
5080 hda_nid_t mixer,
5081 hda_nid_t cap1, hda_nid_t cap2)
5082{
5083 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005084 struct hda_input_mux *imux = &spec->private_imux[0];
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005085 int i, err, idx, type, type_idx = 0;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005086
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005087 for (i = 0; i < cfg->num_inputs; i++) {
Takashi Iwai05f5f472009-08-25 13:10:18 +02005088 hda_nid_t pin;
Takashi Iwai10a20af2010-09-09 16:28:02 +02005089 const char *label;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005090
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005091 pin = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005092 if (!alc_is_input_pin(codec, pin))
5093 continue;
5094
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005095 type = cfg->inputs[i].type;
5096 if (i > 0 && type == cfg->inputs[i - 1].type)
5097 type_idx++;
5098 else
5099 type_idx = 0;
Takashi Iwai10a20af2010-09-09 16:28:02 +02005100 label = hda_get_autocfg_input_label(codec, cfg, i);
Takashi Iwai05f5f472009-08-25 13:10:18 +02005101 if (mixer) {
5102 idx = get_connection_index(codec, mixer, pin);
5103 if (idx >= 0) {
5104 err = new_analog_input(spec, pin,
Takashi Iwai10a20af2010-09-09 16:28:02 +02005105 label, type_idx,
5106 idx, mixer);
Takashi Iwai05f5f472009-08-25 13:10:18 +02005107 if (err < 0)
5108 return err;
5109 }
5110 }
5111
5112 if (!cap1)
5113 continue;
5114 idx = get_connection_index(codec, cap1, pin);
5115 if (idx < 0 && cap2)
5116 idx = get_connection_index(codec, cap2, pin);
Takashi Iwai10a20af2010-09-09 16:28:02 +02005117 if (idx >= 0)
5118 snd_hda_add_imux_item(imux, label, idx, NULL);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005119 }
5120 return 0;
5121}
5122
Takashi Iwai05f5f472009-08-25 13:10:18 +02005123static int alc880_auto_create_input_ctls(struct hda_codec *codec,
5124 const struct auto_pin_cfg *cfg)
5125{
5126 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x08, 0x09);
5127}
5128
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005129static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
5130 unsigned int pin_type)
5131{
5132 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5133 pin_type);
5134 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01005135 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
5136 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005137}
5138
Kailang Yangdf694da2005-12-05 19:42:22 +01005139static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
5140 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005141 int dac_idx)
5142{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005143 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005144 /* need the manual connection? */
5145 if (alc880_is_multi_pin(nid)) {
5146 struct alc_spec *spec = codec->spec;
5147 int idx = alc880_multi_pin_idx(nid);
5148 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
5149 AC_VERB_SET_CONNECT_SEL,
5150 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
5151 }
5152}
5153
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005154static int get_pin_type(int line_out_type)
5155{
5156 if (line_out_type == AUTO_PIN_HP_OUT)
5157 return PIN_HP;
5158 else
5159 return PIN_OUT;
5160}
5161
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005162static void alc880_auto_init_multi_out(struct hda_codec *codec)
5163{
5164 struct alc_spec *spec = codec->spec;
5165 int i;
Kailang Yangea1fb292008-08-26 12:58:38 +02005166
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005167 for (i = 0; i < spec->autocfg.line_outs; i++) {
5168 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005169 int pin_type = get_pin_type(spec->autocfg.line_out_type);
5170 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005171 }
5172}
5173
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005174static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005175{
5176 struct alc_spec *spec = codec->spec;
5177 hda_nid_t pin;
5178
Takashi Iwai82bc9552006-03-21 11:24:42 +01005179 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005180 if (pin) /* connect to front */
5181 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005182 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005183 if (pin) /* connect to front */
5184 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
5185}
5186
5187static void alc880_auto_init_analog_input(struct hda_codec *codec)
5188{
5189 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005190 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005191 int i;
5192
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005193 for (i = 0; i < cfg->num_inputs; i++) {
5194 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005195 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai30ea0982010-09-16 18:47:56 +02005196 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwaie82c0252009-03-23 15:17:38 +01005197 if (nid != ALC880_PIN_CD_NID &&
5198 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005199 snd_hda_codec_write(codec, nid, 0,
5200 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005201 AMP_OUT_MUTE);
5202 }
5203 }
5204}
5205
Takashi Iwai7f311a42010-04-09 17:32:23 +02005206static void alc880_auto_init_input_src(struct hda_codec *codec)
5207{
5208 struct alc_spec *spec = codec->spec;
5209 int c;
5210
5211 for (c = 0; c < spec->num_adc_nids; c++) {
5212 unsigned int mux_idx;
5213 const struct hda_input_mux *imux;
5214 mux_idx = c >= spec->num_mux_defs ? 0 : c;
5215 imux = &spec->input_mux[mux_idx];
5216 if (!imux->num_items && mux_idx > 0)
5217 imux = &spec->input_mux[0];
5218 if (imux)
5219 snd_hda_codec_write(codec, spec->adc_nids[c], 0,
5220 AC_VERB_SET_CONNECT_SEL,
5221 imux->items[0].index);
5222 }
5223}
5224
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005225/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005226/* return 1 if successful, 0 if the proper config is not found,
5227 * or a negative error code
5228 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005229static int alc880_parse_auto_config(struct hda_codec *codec)
5230{
5231 struct alc_spec *spec = codec->spec;
Takashi Iwai757899a2010-07-30 10:48:14 +02005232 int err;
Kailang Yangdf694da2005-12-05 19:42:22 +01005233 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005234
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005235 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
5236 alc880_ignore);
5237 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005238 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005239 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005240 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01005241
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005242 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
5243 if (err < 0)
5244 return err;
5245 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
5246 if (err < 0)
5247 return err;
5248 err = alc880_auto_create_extra_out(spec,
5249 spec->autocfg.speaker_pins[0],
5250 "Speaker");
5251 if (err < 0)
5252 return err;
5253 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
5254 "Headphone");
5255 if (err < 0)
5256 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005257 err = alc880_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005258 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005259 return err;
5260
5261 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
5262
Takashi Iwai757899a2010-07-30 10:48:14 +02005263 alc_auto_parse_digital(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005264
Takashi Iwai603c4012008-07-30 15:01:44 +02005265 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01005266 add_mixer(spec, spec->kctls.list);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005267
Takashi Iwaid88897e2008-10-31 15:01:37 +01005268 add_verb(spec, alc880_volume_init_verbs);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005269
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005270 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005271 spec->input_mux = &spec->private_imux[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005272
Kailang Yang6227cdc2010-02-25 08:36:52 +01005273 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02005274
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005275 return 1;
5276}
5277
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005278/* additional initialization for auto-configuration model */
5279static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005280{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005281 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005282 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005283 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005284 alc880_auto_init_analog_input(codec);
Takashi Iwai7f311a42010-04-09 17:32:23 +02005285 alc880_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +02005286 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005287 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02005288 alc_inithook(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005289}
5290
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005291/* check the ADC/MUX contains all input pins; some ADC/MUX contains only
5292 * one of two digital mic pins, e.g. on ALC272
5293 */
5294static void fixup_automic_adc(struct hda_codec *codec)
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005295{
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005296 struct alc_spec *spec = codec->spec;
5297 int i;
5298
5299 for (i = 0; i < spec->num_adc_nids; i++) {
5300 hda_nid_t cap = spec->capsrc_nids ?
5301 spec->capsrc_nids[i] : spec->adc_nids[i];
5302 int iidx, eidx;
5303
5304 iidx = get_connection_index(codec, cap, spec->int_mic.pin);
5305 if (iidx < 0)
5306 continue;
5307 eidx = get_connection_index(codec, cap, spec->ext_mic.pin);
5308 if (eidx < 0)
5309 continue;
5310 spec->int_mic.mux_idx = iidx;
5311 spec->ext_mic.mux_idx = eidx;
5312 if (spec->capsrc_nids)
5313 spec->capsrc_nids += i;
5314 spec->adc_nids += i;
5315 spec->num_adc_nids = 1;
5316 return;
5317 }
5318 snd_printd(KERN_INFO "hda_codec: %s: "
5319 "No ADC/MUX containing both 0x%x and 0x%x pins\n",
5320 codec->chip_name, spec->int_mic.pin, spec->ext_mic.pin);
5321 spec->auto_mic = 0; /* disable auto-mic to be sure */
5322}
5323
Takashi Iwai748cce42010-08-04 07:37:39 +02005324/* select or unmute the given capsrc route */
5325static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap,
5326 int idx)
5327{
5328 if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
5329 snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
5330 HDA_AMP_MUTE, 0);
5331 } else {
5332 snd_hda_codec_write_cache(codec, cap, 0,
5333 AC_VERB_SET_CONNECT_SEL, idx);
5334 }
5335}
5336
Takashi Iwai840b64c2010-07-13 22:49:01 +02005337/* set the default connection to that pin */
5338static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
5339{
5340 struct alc_spec *spec = codec->spec;
5341 int i;
5342
5343 for (i = 0; i < spec->num_adc_nids; i++) {
5344 hda_nid_t cap = spec->capsrc_nids ?
5345 spec->capsrc_nids[i] : spec->adc_nids[i];
5346 int idx;
5347
5348 idx = get_connection_index(codec, cap, pin);
5349 if (idx < 0)
5350 continue;
Takashi Iwai748cce42010-08-04 07:37:39 +02005351 select_or_unmute_capsrc(codec, cap, idx);
Takashi Iwai840b64c2010-07-13 22:49:01 +02005352 return i; /* return the found index */
5353 }
5354 return -1; /* not found */
5355}
5356
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005357/* choose the ADC/MUX containing the input pin and initialize the setup */
5358static void fixup_single_adc(struct hda_codec *codec)
5359{
5360 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005361 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005362 int i;
5363
5364 /* search for the input pin; there must be only one */
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005365 if (cfg->num_inputs != 1)
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005366 return;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005367 i = init_capsrc_for_pin(codec, cfg->inputs[0].pin);
Takashi Iwai840b64c2010-07-13 22:49:01 +02005368 if (i >= 0) {
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005369 /* use only this ADC */
5370 if (spec->capsrc_nids)
5371 spec->capsrc_nids += i;
5372 spec->adc_nids += i;
5373 spec->num_adc_nids = 1;
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005374 }
5375}
5376
Takashi Iwai840b64c2010-07-13 22:49:01 +02005377/* initialize dual adcs */
5378static void fixup_dual_adc_switch(struct hda_codec *codec)
5379{
5380 struct alc_spec *spec = codec->spec;
5381 init_capsrc_for_pin(codec, spec->ext_mic.pin);
5382 init_capsrc_for_pin(codec, spec->int_mic.pin);
5383}
5384
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005385static void set_capture_mixer(struct hda_codec *codec)
5386{
5387 struct alc_spec *spec = codec->spec;
Takashi Iwaia23b6882009-03-23 15:21:36 +01005388 static struct snd_kcontrol_new *caps[2][3] = {
5389 { alc_capture_mixer_nosrc1,
5390 alc_capture_mixer_nosrc2,
5391 alc_capture_mixer_nosrc3 },
5392 { alc_capture_mixer1,
5393 alc_capture_mixer2,
5394 alc_capture_mixer3 },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005395 };
Takashi Iwaia23b6882009-03-23 15:21:36 +01005396 if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005397 int mux = 0;
Takashi Iwai840b64c2010-07-13 22:49:01 +02005398 int num_adcs = spec->num_adc_nids;
5399 if (spec->dual_adc_switch)
5400 fixup_dual_adc_switch(codec);
5401 else if (spec->auto_mic)
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005402 fixup_automic_adc(codec);
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005403 else if (spec->input_mux) {
5404 if (spec->input_mux->num_items > 1)
5405 mux = 1;
5406 else if (spec->input_mux->num_items == 1)
5407 fixup_single_adc(codec);
5408 }
Takashi Iwai840b64c2010-07-13 22:49:01 +02005409 if (spec->dual_adc_switch)
5410 num_adcs = 1;
5411 spec->cap_mixer = caps[mux][num_adcs - 1];
Takashi Iwaia23b6882009-03-23 15:21:36 +01005412 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005413}
5414
Takashi Iwai66946352010-03-29 17:21:45 +02005415/* fill adc_nids (and capsrc_nids) containing all active input pins */
5416static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids,
5417 int num_nids)
5418{
5419 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005420 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai66946352010-03-29 17:21:45 +02005421 int n;
5422 hda_nid_t fallback_adc = 0, fallback_cap = 0;
5423
5424 for (n = 0; n < num_nids; n++) {
5425 hda_nid_t adc, cap;
5426 hda_nid_t conn[HDA_MAX_NUM_INPUTS];
5427 int nconns, i, j;
5428
5429 adc = nids[n];
5430 if (get_wcaps_type(get_wcaps(codec, adc)) != AC_WID_AUD_IN)
5431 continue;
5432 cap = adc;
5433 nconns = snd_hda_get_connections(codec, cap, conn,
5434 ARRAY_SIZE(conn));
5435 if (nconns == 1) {
5436 cap = conn[0];
5437 nconns = snd_hda_get_connections(codec, cap, conn,
5438 ARRAY_SIZE(conn));
5439 }
5440 if (nconns <= 0)
5441 continue;
5442 if (!fallback_adc) {
5443 fallback_adc = adc;
5444 fallback_cap = cap;
5445 }
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005446 for (i = 0; i < cfg->num_inputs; i++) {
5447 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai66946352010-03-29 17:21:45 +02005448 for (j = 0; j < nconns; j++) {
5449 if (conn[j] == nid)
5450 break;
5451 }
5452 if (j >= nconns)
5453 break;
5454 }
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005455 if (i >= cfg->num_inputs) {
Takashi Iwai66946352010-03-29 17:21:45 +02005456 int num_adcs = spec->num_adc_nids;
5457 spec->private_adc_nids[num_adcs] = adc;
5458 spec->private_capsrc_nids[num_adcs] = cap;
5459 spec->num_adc_nids++;
5460 spec->adc_nids = spec->private_adc_nids;
5461 if (adc != cap)
5462 spec->capsrc_nids = spec->private_capsrc_nids;
5463 }
5464 }
5465 if (!spec->num_adc_nids) {
5466 printk(KERN_WARNING "hda_codec: %s: no valid ADC found;"
Takashi Iwai1f85d722010-03-30 07:48:05 +02005467 " using fallback 0x%x\n",
5468 codec->chip_name, fallback_adc);
Takashi Iwai66946352010-03-29 17:21:45 +02005469 spec->private_adc_nids[0] = fallback_adc;
5470 spec->adc_nids = spec->private_adc_nids;
5471 if (fallback_adc != fallback_cap) {
5472 spec->private_capsrc_nids[0] = fallback_cap;
5473 spec->capsrc_nids = spec->private_adc_nids;
5474 }
5475 }
5476}
5477
Takashi Iwai67d634c2009-11-16 15:35:59 +01005478#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005479#define set_beep_amp(spec, nid, idx, dir) \
5480 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005481
5482static struct snd_pci_quirk beep_white_list[] = {
5483 SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
Takashi Iwai080dc7b2010-09-08 08:38:41 +02005484 SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
Takashi Iwaie096c8e2010-08-03 17:20:35 +02005485 SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005486 {}
5487};
5488
5489static inline int has_cdefine_beep(struct hda_codec *codec)
5490{
5491 struct alc_spec *spec = codec->spec;
5492 const struct snd_pci_quirk *q;
5493 q = snd_pci_quirk_lookup(codec->bus->pci, beep_white_list);
5494 if (q)
5495 return q->value;
5496 return spec->cdefine.enable_pcbeep;
5497}
Takashi Iwai67d634c2009-11-16 15:35:59 +01005498#else
5499#define set_beep_amp(spec, nid, idx, dir) /* NOP */
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005500#define has_cdefine_beep(codec) 0
Takashi Iwai67d634c2009-11-16 15:35:59 +01005501#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005502
5503/*
5504 * OK, here we have finally the patch for ALC880
5505 */
5506
Linus Torvalds1da177e2005-04-16 15:20:36 -07005507static int patch_alc880(struct hda_codec *codec)
5508{
5509 struct alc_spec *spec;
5510 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01005511 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005512
Takashi Iwaie560d8d2005-09-09 14:21:46 +02005513 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514 if (spec == NULL)
5515 return -ENOMEM;
5516
5517 codec->spec = spec;
5518
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005519 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
5520 alc880_models,
5521 alc880_cfg_tbl);
5522 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02005523 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
5524 codec->chip_name);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005525 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005526 }
5527
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005528 if (board_config == ALC880_AUTO) {
5529 /* automatic parse from the BIOS config */
5530 err = alc880_parse_auto_config(codec);
5531 if (err < 0) {
5532 alc_free(codec);
5533 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005534 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005535 printk(KERN_INFO
5536 "hda_codec: Cannot set up configuration "
5537 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005538 board_config = ALC880_3ST;
5539 }
5540 }
5541
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09005542 err = snd_hda_attach_beep_device(codec, 0x1);
5543 if (err < 0) {
5544 alc_free(codec);
5545 return err;
5546 }
5547
Kailang Yangdf694da2005-12-05 19:42:22 +01005548 if (board_config != ALC880_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02005549 setup_preset(codec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005550
Linus Torvalds1da177e2005-04-16 15:20:36 -07005551 spec->stream_analog_playback = &alc880_pcm_analog_playback;
5552 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01005553 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005554
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555 spec->stream_digital_playback = &alc880_pcm_digital_playback;
5556 spec->stream_digital_capture = &alc880_pcm_digital_capture;
5557
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005558 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005559 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01005560 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005561 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +02005562 wcap = get_wcaps_type(wcap);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005563 if (wcap != AC_WID_AUD_IN) {
5564 spec->adc_nids = alc880_adc_nids_alt;
5565 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005566 } else {
5567 spec->adc_nids = alc880_adc_nids;
5568 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005569 }
5570 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005571 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005572 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005573
Takashi Iwai2134ea42008-01-10 16:53:55 +01005574 spec->vmaster_nid = 0x0c;
5575
Linus Torvalds1da177e2005-04-16 15:20:36 -07005576 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005577 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005578 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02005579#ifdef CONFIG_SND_HDA_POWER_SAVE
5580 if (!spec->loopback.amplist)
5581 spec->loopback.amplist = alc880_loopbacks;
5582#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583
5584 return 0;
5585}
5586
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005587
Linus Torvalds1da177e2005-04-16 15:20:36 -07005588/*
5589 * ALC260 support
5590 */
5591
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005592static hda_nid_t alc260_dac_nids[1] = {
5593 /* front */
5594 0x02,
5595};
5596
5597static hda_nid_t alc260_adc_nids[1] = {
5598 /* ADC0 */
5599 0x04,
5600};
5601
Kailang Yangdf694da2005-12-05 19:42:22 +01005602static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005603 /* ADC1 */
5604 0x05,
5605};
5606
Jonathan Woithed57fdac2006-02-28 11:38:35 +01005607/* NIDs used when simultaneous access to both ADCs makes sense. Note that
5608 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
5609 */
5610static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005611 /* ADC0, ADC1 */
5612 0x04, 0x05
5613};
5614
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005615#define ALC260_DIGOUT_NID 0x03
5616#define ALC260_DIGIN_NID 0x06
5617
5618static struct hda_input_mux alc260_capture_source = {
5619 .num_items = 4,
5620 .items = {
5621 { "Mic", 0x0 },
5622 { "Front Mic", 0x1 },
5623 { "Line", 0x2 },
5624 { "CD", 0x4 },
5625 },
5626};
5627
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01005628/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005629 * headphone jack and the internal CD lines since these are the only pins at
5630 * which audio can appear. For flexibility, also allow the option of
5631 * recording the mixer output on the second ADC (ADC0 doesn't have a
5632 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005633 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005634static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
5635 {
5636 .num_items = 3,
5637 .items = {
5638 { "Mic/Line", 0x0 },
5639 { "CD", 0x4 },
5640 { "Headphone", 0x2 },
5641 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005642 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005643 {
5644 .num_items = 4,
5645 .items = {
5646 { "Mic/Line", 0x0 },
5647 { "CD", 0x4 },
5648 { "Headphone", 0x2 },
5649 { "Mixer", 0x5 },
5650 },
5651 },
5652
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005653};
5654
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005655/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
5656 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005657 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005658static struct hda_input_mux alc260_acer_capture_sources[2] = {
5659 {
5660 .num_items = 4,
5661 .items = {
5662 { "Mic", 0x0 },
5663 { "Line", 0x2 },
5664 { "CD", 0x4 },
5665 { "Headphone", 0x5 },
5666 },
5667 },
5668 {
5669 .num_items = 5,
5670 .items = {
5671 { "Mic", 0x0 },
5672 { "Line", 0x2 },
5673 { "CD", 0x4 },
5674 { "Headphone", 0x6 },
5675 { "Mixer", 0x5 },
5676 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005677 },
5678};
Michael Schwingencc959482009-02-22 18:58:45 +01005679
5680/* Maxdata Favorit 100XS */
5681static struct hda_input_mux alc260_favorit100_capture_sources[2] = {
5682 {
5683 .num_items = 2,
5684 .items = {
5685 { "Line/Mic", 0x0 },
5686 { "CD", 0x4 },
5687 },
5688 },
5689 {
5690 .num_items = 3,
5691 .items = {
5692 { "Line/Mic", 0x0 },
5693 { "CD", 0x4 },
5694 { "Mixer", 0x5 },
5695 },
5696 },
5697};
5698
Linus Torvalds1da177e2005-04-16 15:20:36 -07005699/*
5700 * This is just place-holder, so there's something for alc_build_pcms to look
5701 * at when it calculates the maximum number of channels. ALC260 has no mixer
5702 * element which allows changing the channel mode, so the verb list is
5703 * never used.
5704 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01005705static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005706 { 2, NULL },
5707};
5708
Kailang Yangdf694da2005-12-05 19:42:22 +01005709
5710/* Mixer combinations
5711 *
5712 * basic: base_output + input + pc_beep + capture
5713 * HP: base_output + input + capture_alt
5714 * HP_3013: hp_3013 + input + capture
5715 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005716 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01005717 */
5718
5719static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02005720 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005721 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01005722 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5723 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
5724 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5725 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5726 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005727};
Kailang Yangdf694da2005-12-05 19:42:22 +01005728
5729static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005730 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5731 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5732 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5733 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5734 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5735 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5736 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
5737 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005738 { } /* end */
5739};
5740
Takashi Iwaibec15c32008-01-28 18:16:30 +01005741/* update HP, line and mono out pins according to the master switch */
5742static void alc260_hp_master_update(struct hda_codec *codec,
5743 hda_nid_t hp, hda_nid_t line,
5744 hda_nid_t mono)
5745{
5746 struct alc_spec *spec = codec->spec;
5747 unsigned int val = spec->master_sw ? PIN_HP : 0;
5748 /* change HP and line-out pins */
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005749 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005750 val);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005751 snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005752 val);
5753 /* mono (speaker) depending on the HP jack sense */
5754 val = (val && !spec->jack_present) ? PIN_OUT : 0;
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005755 snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005756 val);
5757}
5758
5759static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
5760 struct snd_ctl_elem_value *ucontrol)
5761{
5762 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5763 struct alc_spec *spec = codec->spec;
5764 *ucontrol->value.integer.value = spec->master_sw;
5765 return 0;
5766}
5767
5768static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
5769 struct snd_ctl_elem_value *ucontrol)
5770{
5771 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5772 struct alc_spec *spec = codec->spec;
5773 int val = !!*ucontrol->value.integer.value;
5774 hda_nid_t hp, line, mono;
5775
5776 if (val == spec->master_sw)
5777 return 0;
5778 spec->master_sw = val;
5779 hp = (kcontrol->private_value >> 16) & 0xff;
5780 line = (kcontrol->private_value >> 8) & 0xff;
5781 mono = kcontrol->private_value & 0xff;
5782 alc260_hp_master_update(codec, hp, line, mono);
5783 return 1;
5784}
5785
5786static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
5787 {
5788 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5789 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01005790 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005791 .info = snd_ctl_boolean_mono_info,
5792 .get = alc260_hp_master_sw_get,
5793 .put = alc260_hp_master_sw_put,
5794 .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
5795 },
5796 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5797 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
5798 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5799 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
5800 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
5801 HDA_OUTPUT),
5802 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5803 { } /* end */
5804};
5805
5806static struct hda_verb alc260_hp_unsol_verbs[] = {
5807 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5808 {},
5809};
5810
5811static void alc260_hp_automute(struct hda_codec *codec)
5812{
5813 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01005814
Wu Fengguang864f92b2009-11-18 12:38:02 +08005815 spec->jack_present = snd_hda_jack_detect(codec, 0x10);
Takashi Iwaibec15c32008-01-28 18:16:30 +01005816 alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
5817}
5818
5819static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
5820{
5821 if ((res >> 26) == ALC880_HP_EVENT)
5822 alc260_hp_automute(codec);
5823}
5824
Kailang Yangdf694da2005-12-05 19:42:22 +01005825static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01005826 {
5827 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5828 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01005829 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005830 .info = snd_ctl_boolean_mono_info,
5831 .get = alc260_hp_master_sw_get,
5832 .put = alc260_hp_master_sw_put,
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005833 .private_value = (0x15 << 16) | (0x10 << 8) | 0x11
Takashi Iwaibec15c32008-01-28 18:16:30 +01005834 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005835 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5836 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
5837 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
5838 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
5839 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5840 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01005841 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5842 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02005843 { } /* end */
5844};
5845
Kailang Yang3f878302008-08-26 13:02:23 +02005846static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
5847 .ops = &snd_hda_bind_vol,
5848 .values = {
5849 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
5850 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
5851 HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
5852 0
5853 },
5854};
5855
5856static struct hda_bind_ctls alc260_dc7600_bind_switch = {
5857 .ops = &snd_hda_bind_sw,
5858 .values = {
5859 HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
5860 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
5861 0
5862 },
5863};
5864
5865static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
5866 HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
5867 HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
5868 HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
5869 HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
5870 { } /* end */
5871};
5872
Takashi Iwaibec15c32008-01-28 18:16:30 +01005873static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
5874 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5875 {},
5876};
5877
5878static void alc260_hp_3013_automute(struct hda_codec *codec)
5879{
5880 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01005881
Wu Fengguang864f92b2009-11-18 12:38:02 +08005882 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005883 alc260_hp_master_update(codec, 0x15, 0x10, 0x11);
Takashi Iwaibec15c32008-01-28 18:16:30 +01005884}
5885
5886static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
5887 unsigned int res)
5888{
5889 if ((res >> 26) == ALC880_HP_EVENT)
5890 alc260_hp_3013_automute(codec);
5891}
5892
Kailang Yang3f878302008-08-26 13:02:23 +02005893static void alc260_hp_3012_automute(struct hda_codec *codec)
5894{
Wu Fengguang864f92b2009-11-18 12:38:02 +08005895 unsigned int bits = snd_hda_jack_detect(codec, 0x10) ? 0 : PIN_OUT;
Kailang Yang3f878302008-08-26 13:02:23 +02005896
Kailang Yang3f878302008-08-26 13:02:23 +02005897 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5898 bits);
5899 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5900 bits);
5901 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5902 bits);
5903}
5904
5905static void alc260_hp_3012_unsol_event(struct hda_codec *codec,
5906 unsigned int res)
5907{
5908 if ((res >> 26) == ALC880_HP_EVENT)
5909 alc260_hp_3012_automute(codec);
5910}
5911
5912/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005913 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
5914 */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01005915static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005916 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005917 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005918 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005919 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5920 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5921 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
5922 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005923 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01005924 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5925 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01005926 { } /* end */
5927};
5928
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005929/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
5930 * versions of the ALC260 don't act on requests to enable mic bias from NID
5931 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
5932 * datasheet doesn't mention this restriction. At this stage it's not clear
5933 * whether this behaviour is intentional or is a hardware bug in chip
5934 * revisions available in early 2006. Therefore for now allow the
5935 * "Headphone Jack Mode" control to span all choices, but if it turns out
5936 * that the lack of mic bias for this NID is intentional we could change the
5937 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
5938 *
5939 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
5940 * don't appear to make the mic bias available from the "line" jack, even
5941 * though the NID used for this jack (0x14) can supply it. The theory is
5942 * that perhaps Acer have included blocking capacitors between the ALC260
5943 * and the output jack. If this turns out to be the case for all such
5944 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
5945 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01005946 *
5947 * The C20x Tablet series have a mono internal speaker which is controlled
5948 * via the chip's Mono sum widget and pin complex, so include the necessary
5949 * controls for such models. On models without a "mono speaker" the control
5950 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005951 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005952static struct snd_kcontrol_new alc260_acer_mixer[] = {
5953 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5954 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005955 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01005956 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01005957 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01005958 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01005959 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005960 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5961 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5962 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5963 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5964 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5965 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5966 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5967 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005968 { } /* end */
5969};
5970
Michael Schwingencc959482009-02-22 18:58:45 +01005971/* Maxdata Favorit 100XS: one output and one input (0x12) jack
5972 */
5973static struct snd_kcontrol_new alc260_favorit100_mixer[] = {
5974 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5975 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
5976 ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
5977 HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5978 HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5979 ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5980 { } /* end */
5981};
5982
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005983/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
5984 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
5985 */
5986static struct snd_kcontrol_new alc260_will_mixer[] = {
5987 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5988 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
5989 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5990 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5991 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5992 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5993 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5994 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
5995 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5996 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005997 { } /* end */
5998};
5999
6000/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
6001 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
6002 */
6003static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
6004 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6005 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
6006 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6007 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6008 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6009 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
6010 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
6011 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6012 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6013 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
6014 { } /* end */
6015};
6016
Kailang Yangdf694da2005-12-05 19:42:22 +01006017/*
6018 * initialization verbs
6019 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006020static struct hda_verb alc260_init_verbs[] = {
6021 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006022 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006023 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006024 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006025 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006026 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006027 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006028 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006029 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02006030 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006031 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01006032 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006033 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02006034 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006035 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02006036 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006037 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02006038 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6039 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02006040 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006041 /* set connection select to line in (default select for this ADC) */
6042 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02006043 /* mute capture amp left and right */
6044 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6045 /* set connection select to line in (default select for this ADC) */
6046 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02006047 /* set vol=0 Line-Out mixer amp left and right */
6048 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6049 /* unmute pin widget amp left and right (no gain on this amp) */
6050 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6051 /* set vol=0 HP mixer amp left and right */
6052 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6053 /* unmute pin widget amp left and right (no gain on this amp) */
6054 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6055 /* set vol=0 Mono mixer amp left and right */
6056 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6057 /* unmute pin widget amp left and right (no gain on this amp) */
6058 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6059 /* unmute LINE-2 out pin */
6060 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006061 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6062 * Line In 2 = 0x03
6063 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006064 /* mute analog inputs */
6065 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6066 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6067 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6068 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6069 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02006071 /* mute Front out path */
6072 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6073 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6074 /* mute Headphone out path */
6075 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6076 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6077 /* mute Mono out path */
6078 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6079 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006080 { }
6081};
6082
Takashi Iwai474167d2006-05-17 17:17:43 +02006083#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01006084static struct hda_verb alc260_hp_init_verbs[] = {
6085 /* Headphone and output */
6086 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
6087 /* mono output */
6088 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6089 /* Mic1 (rear panel) pin widget for input and vref at 80% */
6090 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6091 /* Mic2 (front panel) pin widget for input and vref at 80% */
6092 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6093 /* Line In pin widget for input */
6094 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6095 /* Line-2 pin widget for output */
6096 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6097 /* CD pin widget for input */
6098 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6099 /* unmute amp left and right */
6100 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
6101 /* set connection select to line in (default select for this ADC) */
6102 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
6103 /* unmute Line-Out mixer amp left and right (volume = 0) */
6104 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6105 /* mute pin widget amp left and right (no gain on this amp) */
6106 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
6107 /* unmute HP mixer amp left and right (volume = 0) */
6108 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6109 /* mute pin widget amp left and right (no gain on this amp) */
6110 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006111 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6112 * Line In 2 = 0x03
6113 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006114 /* mute analog inputs */
6115 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6116 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6117 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6118 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6119 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006120 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
6121 /* Unmute Front out path */
6122 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6123 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6124 /* Unmute Headphone out path */
6125 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6126 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6127 /* Unmute Mono out path */
6128 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6129 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6130 { }
6131};
Takashi Iwai474167d2006-05-17 17:17:43 +02006132#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01006133
6134static struct hda_verb alc260_hp_3013_init_verbs[] = {
6135 /* Line out and output */
6136 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6137 /* mono output */
6138 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6139 /* Mic1 (rear panel) pin widget for input and vref at 80% */
6140 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6141 /* Mic2 (front panel) pin widget for input and vref at 80% */
6142 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6143 /* Line In pin widget for input */
6144 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6145 /* Headphone pin widget for output */
6146 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
6147 /* CD pin widget for input */
6148 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6149 /* unmute amp left and right */
6150 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
6151 /* set connection select to line in (default select for this ADC) */
6152 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
6153 /* unmute Line-Out mixer amp left and right (volume = 0) */
6154 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6155 /* mute pin widget amp left and right (no gain on this amp) */
6156 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
6157 /* unmute HP mixer amp left and right (volume = 0) */
6158 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6159 /* mute pin widget amp left and right (no gain on this amp) */
6160 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006161 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6162 * Line In 2 = 0x03
6163 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006164 /* mute analog inputs */
6165 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6166 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6167 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6168 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6169 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006170 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
6171 /* Unmute Front out path */
6172 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6173 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6174 /* Unmute Headphone out path */
6175 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6176 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6177 /* Unmute Mono out path */
6178 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6179 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6180 { }
6181};
6182
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006183/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006184 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
6185 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006186 */
6187static struct hda_verb alc260_fujitsu_init_verbs[] = {
6188 /* Disable all GPIOs */
6189 {0x01, AC_VERB_SET_GPIO_MASK, 0},
6190 /* Internal speaker is connected to headphone pin */
6191 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6192 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
6193 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006194 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
6195 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6196 /* Ensure all other unused pins are disabled and muted. */
6197 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6198 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006199 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006200 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006201 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006202 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6203 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6204 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006205
Jonathan Woithef7ace402006-02-28 11:46:14 +01006206 /* Disable digital (SPDIF) pins */
6207 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6208 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006209
Kailang Yangea1fb292008-08-26 12:58:38 +02006210 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
Jonathan Woithef7ace402006-02-28 11:46:14 +01006211 * when acting as an output.
6212 */
6213 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6214
6215 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01006216 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6217 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6218 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6219 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6220 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6221 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6222 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6223 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6224 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006225
Jonathan Woithef7ace402006-02-28 11:46:14 +01006226 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
6227 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6228 /* Unmute Line1 pin widget output buffer since it starts as an output.
6229 * If the pin mode is changed by the user the pin mode control will
6230 * take care of enabling the pin's input/output buffers as needed.
6231 * Therefore there's no need to enable the input buffer at this
6232 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006233 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01006234 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +02006235 /* Unmute input buffer of pin widget used for Line-in (no equiv
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006236 * mixer ctrl)
6237 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01006238 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006239
Jonathan Woithef7ace402006-02-28 11:46:14 +01006240 /* Mute capture amp left and right */
6241 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006242 /* Set ADC connection select to match default mixer setting - line
Jonathan Woithef7ace402006-02-28 11:46:14 +01006243 * in (on mic1 pin)
6244 */
6245 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006246
Jonathan Woithef7ace402006-02-28 11:46:14 +01006247 /* Do the same for the second ADC: mute capture input amp and
6248 * set ADC connection to line in (on mic1 pin)
6249 */
6250 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6251 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006252
Jonathan Woithef7ace402006-02-28 11:46:14 +01006253 /* Mute all inputs to mixer widget (even unconnected ones) */
6254 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6255 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6256 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6257 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6258 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6259 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6260 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6261 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01006262
6263 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006264};
6265
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006266/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
6267 * similar laptops (adapted from Fujitsu init verbs).
6268 */
6269static struct hda_verb alc260_acer_init_verbs[] = {
6270 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
6271 * the headphone jack. Turn this on and rely on the standard mute
6272 * methods whenever the user wants to turn these outputs off.
6273 */
6274 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6275 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6276 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
6277 /* Internal speaker/Headphone jack is connected to Line-out pin */
6278 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6279 /* Internal microphone/Mic jack is connected to Mic1 pin */
6280 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
6281 /* Line In jack is connected to Line1 pin */
6282 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01006283 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
6284 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006285 /* Ensure all other unused pins are disabled and muted. */
6286 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6287 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006288 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6289 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6290 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6291 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6292 /* Disable digital (SPDIF) pins */
6293 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6294 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6295
Kailang Yangea1fb292008-08-26 12:58:38 +02006296 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006297 * bus when acting as outputs.
6298 */
6299 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6300 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6301
6302 /* Start with output sum widgets muted and their output gains at min */
6303 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6304 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6305 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6306 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6307 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6308 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6309 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6310 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6311 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6312
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006313 /* Unmute Line-out pin widget amp left and right
6314 * (no equiv mixer ctrl)
6315 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006316 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01006317 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
6318 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006319 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
6320 * inputs. If the pin mode is changed by the user the pin mode control
6321 * will take care of enabling the pin's input/output buffers as needed.
6322 * Therefore there's no need to enable the input buffer at this
6323 * stage.
6324 */
6325 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6326 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6327
6328 /* Mute capture amp left and right */
6329 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6330 /* Set ADC connection select to match default mixer setting - mic
6331 * (on mic1 pin)
6332 */
6333 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6334
6335 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006336 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006337 */
6338 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006339 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006340
6341 /* Mute all inputs to mixer widget (even unconnected ones) */
6342 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6343 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6344 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6345 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6346 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6347 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6348 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6349 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6350
6351 { }
6352};
6353
Michael Schwingencc959482009-02-22 18:58:45 +01006354/* Initialisation sequence for Maxdata Favorit 100XS
6355 * (adapted from Acer init verbs).
6356 */
6357static struct hda_verb alc260_favorit100_init_verbs[] = {
6358 /* GPIO 0 enables the output jack.
6359 * Turn this on and rely on the standard mute
6360 * methods whenever the user wants to turn these outputs off.
6361 */
6362 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6363 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6364 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
6365 /* Line/Mic input jack is connected to Mic1 pin */
6366 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
6367 /* Ensure all other unused pins are disabled and muted. */
6368 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6369 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6370 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6371 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6372 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6373 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6374 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6375 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6376 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6377 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6378 /* Disable digital (SPDIF) pins */
6379 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6380 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6381
6382 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
6383 * bus when acting as outputs.
6384 */
6385 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6386 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6387
6388 /* Start with output sum widgets muted and their output gains at min */
6389 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6390 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6391 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6392 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6393 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6394 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6395 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6396 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6397 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6398
6399 /* Unmute Line-out pin widget amp left and right
6400 * (no equiv mixer ctrl)
6401 */
6402 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6403 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
6404 * inputs. If the pin mode is changed by the user the pin mode control
6405 * will take care of enabling the pin's input/output buffers as needed.
6406 * Therefore there's no need to enable the input buffer at this
6407 * stage.
6408 */
6409 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6410
6411 /* Mute capture amp left and right */
6412 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6413 /* Set ADC connection select to match default mixer setting - mic
6414 * (on mic1 pin)
6415 */
6416 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6417
6418 /* Do similar with the second ADC: mute capture input amp and
6419 * set ADC connection to mic to match ALSA's default state.
6420 */
6421 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6422 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6423
6424 /* Mute all inputs to mixer widget (even unconnected ones) */
6425 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6426 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6427 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6428 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6429 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6430 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6431 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6432 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6433
6434 { }
6435};
6436
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006437static struct hda_verb alc260_will_verbs[] = {
6438 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6439 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
6440 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
6441 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
6442 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
6443 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
6444 {}
6445};
6446
6447static struct hda_verb alc260_replacer_672v_verbs[] = {
6448 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
6449 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
6450 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
6451
6452 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6453 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6454 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6455
6456 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6457 {}
6458};
6459
6460/* toggle speaker-output according to the hp-jack state */
6461static void alc260_replacer_672v_automute(struct hda_codec *codec)
6462{
6463 unsigned int present;
6464
6465 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
Wu Fengguang864f92b2009-11-18 12:38:02 +08006466 present = snd_hda_jack_detect(codec, 0x0f);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006467 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006468 snd_hda_codec_write_cache(codec, 0x01, 0,
6469 AC_VERB_SET_GPIO_DATA, 1);
6470 snd_hda_codec_write_cache(codec, 0x0f, 0,
6471 AC_VERB_SET_PIN_WIDGET_CONTROL,
6472 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006473 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006474 snd_hda_codec_write_cache(codec, 0x01, 0,
6475 AC_VERB_SET_GPIO_DATA, 0);
6476 snd_hda_codec_write_cache(codec, 0x0f, 0,
6477 AC_VERB_SET_PIN_WIDGET_CONTROL,
6478 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006479 }
6480}
6481
6482static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
6483 unsigned int res)
6484{
6485 if ((res >> 26) == ALC880_HP_EVENT)
6486 alc260_replacer_672v_automute(codec);
6487}
6488
Kailang Yang3f878302008-08-26 13:02:23 +02006489static struct hda_verb alc260_hp_dc7600_verbs[] = {
6490 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
6491 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
6492 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6493 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6494 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6495 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6496 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6497 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6498 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6499 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6500 {}
6501};
6502
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006503/* Test configuration for debugging, modelled after the ALC880 test
6504 * configuration.
6505 */
6506#ifdef CONFIG_SND_DEBUG
6507static hda_nid_t alc260_test_dac_nids[1] = {
6508 0x02,
6509};
6510static hda_nid_t alc260_test_adc_nids[2] = {
6511 0x04, 0x05,
6512};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006513/* For testing the ALC260, each input MUX needs its own definition since
Kailang Yangea1fb292008-08-26 12:58:38 +02006514 * the signal assignments are different. This assumes that the first ADC
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006515 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01006516 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006517static struct hda_input_mux alc260_test_capture_sources[2] = {
6518 {
6519 .num_items = 7,
6520 .items = {
6521 { "MIC1 pin", 0x0 },
6522 { "MIC2 pin", 0x1 },
6523 { "LINE1 pin", 0x2 },
6524 { "LINE2 pin", 0x3 },
6525 { "CD pin", 0x4 },
6526 { "LINE-OUT pin", 0x5 },
6527 { "HP-OUT pin", 0x6 },
6528 },
6529 },
6530 {
6531 .num_items = 8,
6532 .items = {
6533 { "MIC1 pin", 0x0 },
6534 { "MIC2 pin", 0x1 },
6535 { "LINE1 pin", 0x2 },
6536 { "LINE2 pin", 0x3 },
6537 { "CD pin", 0x4 },
6538 { "Mixer", 0x5 },
6539 { "LINE-OUT pin", 0x6 },
6540 { "HP-OUT pin", 0x7 },
6541 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006542 },
6543};
6544static struct snd_kcontrol_new alc260_test_mixer[] = {
6545 /* Output driver widgets */
6546 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
6547 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
6548 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6549 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
6550 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6551 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
6552
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006553 /* Modes for retasking pin widgets
6554 * Note: the ALC260 doesn't seem to act on requests to enable mic
6555 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
6556 * mention this restriction. At this stage it's not clear whether
6557 * this behaviour is intentional or is a hardware bug in chip
6558 * revisions available at least up until early 2006. Therefore for
6559 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
6560 * choices, but if it turns out that the lack of mic bias for these
6561 * NIDs is intentional we could change their modes from
6562 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
6563 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006564 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
6565 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
6566 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
6567 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
6568 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
6569 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
6570
6571 /* Loopback mixer controls */
6572 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
6573 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
6574 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
6575 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
6576 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
6577 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
6578 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
6579 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
6580 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6581 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006582 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
6583 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
6584 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
6585 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01006586
6587 /* Controls for GPIO pins, assuming they are configured as outputs */
6588 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
6589 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
6590 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
6591 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
6592
Jonathan Woithe92621f12006-02-28 11:47:47 +01006593 /* Switches to allow the digital IO pins to be enabled. The datasheet
6594 * is ambigious as to which NID is which; testing on laptops which
Kailang Yangea1fb292008-08-26 12:58:38 +02006595 * make this output available should provide clarification.
Jonathan Woithe92621f12006-02-28 11:47:47 +01006596 */
6597 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
6598 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
6599
Jonathan Woithef8225f62008-01-08 12:16:54 +01006600 /* A switch allowing EAPD to be enabled. Some laptops seem to use
6601 * this output to turn on an external amplifier.
6602 */
6603 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
6604 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
6605
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006606 { } /* end */
6607};
6608static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01006609 /* Enable all GPIOs as outputs with an initial value of 0 */
6610 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
6611 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6612 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
6613
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006614 /* Enable retasking pins as output, initially without power amp */
6615 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6616 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6617 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6618 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6619 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6620 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6621
Jonathan Woithe92621f12006-02-28 11:47:47 +01006622 /* Disable digital (SPDIF) pins initially, but users can enable
6623 * them via a mixer switch. In the case of SPDIF-out, this initverb
6624 * payload also sets the generation to 0, output to be in "consumer"
6625 * PCM format, copyright asserted, no pre-emphasis and no validity
6626 * control.
6627 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006628 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6629 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6630
Kailang Yangea1fb292008-08-26 12:58:38 +02006631 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006632 * OUT1 sum bus when acting as an output.
6633 */
6634 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6635 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
6636 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6637 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
6638
6639 /* Start with output sum widgets muted and their output gains at min */
6640 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6641 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6642 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6643 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6644 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6645 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6646 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6647 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6648 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6649
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006650 /* Unmute retasking pin widget output buffers since the default
6651 * state appears to be output. As the pin mode is changed by the
6652 * user the pin mode control will take care of enabling the pin's
6653 * input/output buffers as needed.
6654 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006655 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6656 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6657 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6658 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6659 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6660 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6661 /* Also unmute the mono-out pin widget */
6662 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6663
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006664 /* Mute capture amp left and right */
6665 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006666 /* Set ADC connection select to match default mixer setting (mic1
6667 * pin)
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006668 */
6669 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6670
6671 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01006672 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006673 */
6674 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6675 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6676
6677 /* Mute all inputs to mixer widget (even unconnected ones) */
6678 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6679 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6680 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6681 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6682 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6683 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6684 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6685 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6686
6687 { }
6688};
6689#endif
6690
Takashi Iwai63300792008-01-24 15:31:36 +01006691#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
6692#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07006693
Takashi Iwaia3bcba32005-12-06 19:05:29 +01006694#define alc260_pcm_digital_playback alc880_pcm_digital_playback
6695#define alc260_pcm_digital_capture alc880_pcm_digital_capture
6696
Kailang Yangdf694da2005-12-05 19:42:22 +01006697/*
6698 * for BIOS auto-configuration
6699 */
6700
6701static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai863b4512008-10-21 17:01:47 +02006702 const char *pfx, int *vol_bits)
Kailang Yangdf694da2005-12-05 19:42:22 +01006703{
6704 hda_nid_t nid_vol;
6705 unsigned long vol_val, sw_val;
Kailang Yangdf694da2005-12-05 19:42:22 +01006706 int err;
6707
6708 if (nid >= 0x0f && nid < 0x11) {
6709 nid_vol = nid - 0x7;
6710 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
6711 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
6712 } else if (nid == 0x11) {
6713 nid_vol = nid - 0x7;
6714 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
6715 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
6716 } else if (nid >= 0x12 && nid <= 0x15) {
6717 nid_vol = 0x08;
6718 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
6719 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
6720 } else
6721 return 0; /* N/A */
Kailang Yangea1fb292008-08-26 12:58:38 +02006722
Takashi Iwai863b4512008-10-21 17:01:47 +02006723 if (!(*vol_bits & (1 << nid_vol))) {
6724 /* first control for the volume widget */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02006725 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, vol_val);
Takashi Iwai863b4512008-10-21 17:01:47 +02006726 if (err < 0)
6727 return err;
6728 *vol_bits |= (1 << nid_vol);
6729 }
Takashi Iwai0afe5f82009-10-02 09:20:00 +02006730 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, sw_val);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006731 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006732 return err;
6733 return 1;
6734}
6735
6736/* add playback controls from the parsed DAC table */
6737static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
6738 const struct auto_pin_cfg *cfg)
6739{
6740 hda_nid_t nid;
6741 int err;
Takashi Iwai863b4512008-10-21 17:01:47 +02006742 int vols = 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01006743
6744 spec->multiout.num_dacs = 1;
6745 spec->multiout.dac_nids = spec->private_dac_nids;
6746 spec->multiout.dac_nids[0] = 0x02;
6747
6748 nid = cfg->line_out_pins[0];
6749 if (nid) {
Takashi Iwai23112d62009-08-25 16:07:08 +02006750 const char *pfx;
6751 if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
6752 pfx = "Master";
6753 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
6754 pfx = "Speaker";
6755 else
6756 pfx = "Front";
6757 err = alc260_add_playback_controls(spec, nid, pfx, &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006758 if (err < 0)
6759 return err;
6760 }
6761
Takashi Iwai82bc9552006-03-21 11:24:42 +01006762 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006763 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02006764 err = alc260_add_playback_controls(spec, nid, "Speaker", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006765 if (err < 0)
6766 return err;
6767 }
6768
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006769 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006770 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02006771 err = alc260_add_playback_controls(spec, nid, "Headphone",
6772 &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006773 if (err < 0)
6774 return err;
6775 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006776 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01006777}
6778
6779/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +02006780static int alc260_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yangdf694da2005-12-05 19:42:22 +01006781 const struct auto_pin_cfg *cfg)
6782{
Takashi Iwai05f5f472009-08-25 13:10:18 +02006783 return alc_auto_create_input_ctls(codec, cfg, 0x07, 0x04, 0x05);
Kailang Yangdf694da2005-12-05 19:42:22 +01006784}
6785
6786static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
6787 hda_nid_t nid, int pin_type,
6788 int sel_idx)
6789{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006790 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006791 /* need the manual connection? */
6792 if (nid >= 0x12) {
6793 int idx = nid - 0x12;
6794 snd_hda_codec_write(codec, idx + 0x0b, 0,
6795 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01006796 }
6797}
6798
6799static void alc260_auto_init_multi_out(struct hda_codec *codec)
6800{
6801 struct alc_spec *spec = codec->spec;
6802 hda_nid_t nid;
6803
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006804 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006805 if (nid) {
6806 int pin_type = get_pin_type(spec->autocfg.line_out_type);
6807 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
6808 }
Kailang Yangea1fb292008-08-26 12:58:38 +02006809
Takashi Iwai82bc9552006-03-21 11:24:42 +01006810 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006811 if (nid)
6812 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
6813
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006814 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006815 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006816 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006817}
Kailang Yangdf694da2005-12-05 19:42:22 +01006818
6819#define ALC260_PIN_CD_NID 0x16
6820static void alc260_auto_init_analog_input(struct hda_codec *codec)
6821{
6822 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02006823 struct auto_pin_cfg *cfg = &spec->autocfg;
Kailang Yangdf694da2005-12-05 19:42:22 +01006824 int i;
6825
Takashi Iwai66ceeb62010-08-30 13:05:52 +02006826 for (i = 0; i < cfg->num_inputs; i++) {
6827 hda_nid_t nid = cfg->inputs[i].pin;
Kailang Yangdf694da2005-12-05 19:42:22 +01006828 if (nid >= 0x12) {
Takashi Iwai30ea0982010-09-16 18:47:56 +02006829 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwaie82c0252009-03-23 15:17:38 +01006830 if (nid != ALC260_PIN_CD_NID &&
6831 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006832 snd_hda_codec_write(codec, nid, 0,
6833 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01006834 AMP_OUT_MUTE);
6835 }
6836 }
6837}
6838
Takashi Iwai7f311a42010-04-09 17:32:23 +02006839#define alc260_auto_init_input_src alc880_auto_init_input_src
6840
Kailang Yangdf694da2005-12-05 19:42:22 +01006841/*
6842 * generic initialization of ADC, input mixers and output mixers
6843 */
6844static struct hda_verb alc260_volume_init_verbs[] = {
6845 /*
6846 * Unmute ADC0-1 and set the default input to mic-in
6847 */
6848 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6849 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6850 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6851 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006852
Kailang Yangdf694da2005-12-05 19:42:22 +01006853 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
6854 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006855 * Note: PASD motherboards uses the Line In 2 as the input for
6856 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01006857 */
6858 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006859 /* mute analog inputs */
6860 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6861 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6862 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6863 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6864 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006865
6866 /*
6867 * Set up output mixers (0x08 - 0x0a)
6868 */
6869 /* set vol=0 to output mixers */
6870 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6871 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6872 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6873 /* set up input amps for analog loopback */
6874 /* Amp Indices: DAC = 0, mixer = 1 */
6875 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6876 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6877 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6878 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6879 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6880 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006881
Kailang Yangdf694da2005-12-05 19:42:22 +01006882 { }
6883};
6884
6885static int alc260_parse_auto_config(struct hda_codec *codec)
6886{
6887 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006888 int err;
6889 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
6890
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006891 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
6892 alc260_ignore);
6893 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006894 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006895 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
6896 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01006897 return err;
Takashi Iwai603c4012008-07-30 15:01:44 +02006898 if (!spec->kctls.list)
Kailang Yangdf694da2005-12-05 19:42:22 +01006899 return 0; /* can't find valid BIOS pin config */
Takashi Iwai05f5f472009-08-25 13:10:18 +02006900 err = alc260_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006901 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006902 return err;
6903
6904 spec->multiout.max_channels = 2;
6905
Takashi Iwai0852d7a2009-02-11 11:35:15 +01006906 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +01006907 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
Takashi Iwai603c4012008-07-30 15:01:44 +02006908 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01006909 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +01006910
Takashi Iwaid88897e2008-10-31 15:01:37 +01006911 add_verb(spec, alc260_volume_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +01006912
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006913 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02006914 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006915
Kailang Yang6227cdc2010-02-25 08:36:52 +01006916 alc_ssid_check(codec, 0x10, 0x15, 0x0f, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02006917
Kailang Yangdf694da2005-12-05 19:42:22 +01006918 return 1;
6919}
6920
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006921/* additional initialization for auto-configuration model */
6922static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01006923{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006924 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006925 alc260_auto_init_multi_out(codec);
6926 alc260_auto_init_analog_input(codec);
Takashi Iwai7f311a42010-04-09 17:32:23 +02006927 alc260_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +02006928 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006929 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02006930 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01006931}
6932
Takashi Iwaicb53c622007-08-10 17:21:45 +02006933#ifdef CONFIG_SND_HDA_POWER_SAVE
6934static struct hda_amp_list alc260_loopbacks[] = {
6935 { 0x07, HDA_INPUT, 0 },
6936 { 0x07, HDA_INPUT, 1 },
6937 { 0x07, HDA_INPUT, 2 },
6938 { 0x07, HDA_INPUT, 3 },
6939 { 0x07, HDA_INPUT, 4 },
6940 { } /* end */
6941};
6942#endif
6943
Kailang Yangdf694da2005-12-05 19:42:22 +01006944/*
Takashi Iwaifc091762010-08-04 23:53:36 +02006945 * Pin config fixes
6946 */
6947enum {
6948 PINFIX_HP_DC5750,
6949};
6950
Takashi Iwaifc091762010-08-04 23:53:36 +02006951static const struct alc_fixup alc260_fixups[] = {
6952 [PINFIX_HP_DC5750] = {
Takashi Iwai73413b12010-08-30 09:39:57 +02006953 .pins = (const struct alc_pincfg[]) {
6954 { 0x11, 0x90130110 }, /* speaker */
6955 { }
6956 }
Takashi Iwaifc091762010-08-04 23:53:36 +02006957 },
6958};
6959
6960static struct snd_pci_quirk alc260_fixup_tbl[] = {
6961 SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750),
6962 {}
6963};
6964
6965/*
Kailang Yangdf694da2005-12-05 19:42:22 +01006966 * ALC260 configurations
6967 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006968static const char *alc260_models[ALC260_MODEL_LAST] = {
6969 [ALC260_BASIC] = "basic",
6970 [ALC260_HP] = "hp",
6971 [ALC260_HP_3013] = "hp-3013",
Takashi Iwai2922c9a2008-08-27 18:12:42 +02006972 [ALC260_HP_DC7600] = "hp-dc7600",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006973 [ALC260_FUJITSU_S702X] = "fujitsu",
6974 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006975 [ALC260_WILL] = "will",
6976 [ALC260_REPLACER_672V] = "replacer",
Michael Schwingencc959482009-02-22 18:58:45 +01006977 [ALC260_FAVORIT100] = "favorit100",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006978#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006979 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006980#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006981 [ALC260_AUTO] = "auto",
6982};
6983
6984static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01006985 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Daniel T Chen950200e2009-12-13 14:11:02 -05006986 SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006987 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Michael Schwingencc959482009-02-22 18:58:45 +01006988 SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100),
Takashi Iwai9720b712007-03-13 21:46:23 +01006989 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwai4ac55982009-11-10 16:08:45 +01006990 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006991 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
Jaroslav Kysela34ec8a02008-07-10 14:49:19 +02006992 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
Kailang Yang3f878302008-08-26 13:02:23 +02006993 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006994 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
6995 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
6996 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
6997 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
6998 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
6999 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
7000 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
7001 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
7002 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007003 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007004 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02007005 {}
7006};
7007
Kailang Yangdf694da2005-12-05 19:42:22 +01007008static struct alc_config_preset alc260_presets[] = {
7009 [ALC260_BASIC] = {
7010 .mixers = { alc260_base_output_mixer,
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007011 alc260_input_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01007012 .init_verbs = { alc260_init_verbs },
7013 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7014 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007015 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
Takashi Iwai9c4cc0b2010-03-15 09:07:52 +01007016 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01007017 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7018 .channel_mode = alc260_modes,
7019 .input_mux = &alc260_capture_source,
7020 },
7021 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01007022 .mixers = { alc260_hp_output_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007023 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01007024 .init_verbs = { alc260_init_verbs,
7025 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01007026 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7027 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007028 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7029 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01007030 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7031 .channel_mode = alc260_modes,
7032 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01007033 .unsol_event = alc260_hp_unsol_event,
7034 .init_hook = alc260_hp_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01007035 },
Kailang Yang3f878302008-08-26 13:02:23 +02007036 [ALC260_HP_DC7600] = {
7037 .mixers = { alc260_hp_dc7600_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007038 alc260_input_mixer },
Kailang Yang3f878302008-08-26 13:02:23 +02007039 .init_verbs = { alc260_init_verbs,
7040 alc260_hp_dc7600_verbs },
7041 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7042 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007043 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7044 .adc_nids = alc260_adc_nids_alt,
Kailang Yang3f878302008-08-26 13:02:23 +02007045 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7046 .channel_mode = alc260_modes,
7047 .input_mux = &alc260_capture_source,
7048 .unsol_event = alc260_hp_3012_unsol_event,
7049 .init_hook = alc260_hp_3012_automute,
7050 },
Kailang Yangdf694da2005-12-05 19:42:22 +01007051 [ALC260_HP_3013] = {
7052 .mixers = { alc260_hp_3013_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007053 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01007054 .init_verbs = { alc260_hp_3013_init_verbs,
7055 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01007056 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7057 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007058 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7059 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01007060 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7061 .channel_mode = alc260_modes,
7062 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01007063 .unsol_event = alc260_hp_3013_unsol_event,
7064 .init_hook = alc260_hp_3013_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01007065 },
7066 [ALC260_FUJITSU_S702X] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007067 .mixers = { alc260_fujitsu_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01007068 .init_verbs = { alc260_fujitsu_init_verbs },
7069 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7070 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01007071 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7072 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01007073 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7074 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007075 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
7076 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01007077 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007078 [ALC260_ACER] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007079 .mixers = { alc260_acer_mixer },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007080 .init_verbs = { alc260_acer_init_verbs },
7081 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7082 .dac_nids = alc260_dac_nids,
7083 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7084 .adc_nids = alc260_dual_adc_nids,
7085 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7086 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007087 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
7088 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007089 },
Michael Schwingencc959482009-02-22 18:58:45 +01007090 [ALC260_FAVORIT100] = {
7091 .mixers = { alc260_favorit100_mixer },
7092 .init_verbs = { alc260_favorit100_init_verbs },
7093 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7094 .dac_nids = alc260_dac_nids,
7095 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7096 .adc_nids = alc260_dual_adc_nids,
7097 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7098 .channel_mode = alc260_modes,
7099 .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources),
7100 .input_mux = alc260_favorit100_capture_sources,
7101 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007102 [ALC260_WILL] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007103 .mixers = { alc260_will_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007104 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
7105 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7106 .dac_nids = alc260_dac_nids,
7107 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
7108 .adc_nids = alc260_adc_nids,
7109 .dig_out_nid = ALC260_DIGOUT_NID,
7110 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7111 .channel_mode = alc260_modes,
7112 .input_mux = &alc260_capture_source,
7113 },
7114 [ALC260_REPLACER_672V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007115 .mixers = { alc260_replacer_672v_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007116 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
7117 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7118 .dac_nids = alc260_dac_nids,
7119 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
7120 .adc_nids = alc260_adc_nids,
7121 .dig_out_nid = ALC260_DIGOUT_NID,
7122 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7123 .channel_mode = alc260_modes,
7124 .input_mux = &alc260_capture_source,
7125 .unsol_event = alc260_replacer_672v_unsol_event,
7126 .init_hook = alc260_replacer_672v_automute,
7127 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007128#ifdef CONFIG_SND_DEBUG
7129 [ALC260_TEST] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007130 .mixers = { alc260_test_mixer },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007131 .init_verbs = { alc260_test_init_verbs },
7132 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
7133 .dac_nids = alc260_test_dac_nids,
7134 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
7135 .adc_nids = alc260_test_adc_nids,
7136 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7137 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007138 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
7139 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007140 },
7141#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01007142};
7143
Linus Torvalds1da177e2005-04-16 15:20:36 -07007144static int patch_alc260(struct hda_codec *codec)
7145{
7146 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007147 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007148
Takashi Iwaie560d8d2005-09-09 14:21:46 +02007149 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007150 if (spec == NULL)
7151 return -ENOMEM;
7152
7153 codec->spec = spec;
7154
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007155 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
7156 alc260_models,
7157 alc260_cfg_tbl);
7158 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02007159 snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai6c627f32009-05-18 12:33:36 +02007160 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +01007161 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02007162 }
7163
Takashi Iwaifc091762010-08-04 23:53:36 +02007164 if (board_config == ALC260_AUTO)
7165 alc_pick_fixup(codec, alc260_fixup_tbl, alc260_fixups, 1);
7166
Kailang Yangdf694da2005-12-05 19:42:22 +01007167 if (board_config == ALC260_AUTO) {
7168 /* automatic parse from the BIOS config */
7169 err = alc260_parse_auto_config(codec);
7170 if (err < 0) {
7171 alc_free(codec);
7172 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007173 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007174 printk(KERN_INFO
7175 "hda_codec: Cannot set up configuration "
7176 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01007177 board_config = ALC260_BASIC;
7178 }
Takashi Iwai16ded522005-06-10 19:58:24 +02007179 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007180
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09007181 err = snd_hda_attach_beep_device(codec, 0x1);
7182 if (err < 0) {
7183 alc_free(codec);
7184 return err;
7185 }
7186
Kailang Yangdf694da2005-12-05 19:42:22 +01007187 if (board_config != ALC260_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02007188 setup_preset(codec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007189
Linus Torvalds1da177e2005-04-16 15:20:36 -07007190 spec->stream_analog_playback = &alc260_pcm_analog_playback;
7191 spec->stream_analog_capture = &alc260_pcm_analog_capture;
Jonathan Woithe53bacfb2010-08-08 00:17:05 +09307192 spec->stream_analog_alt_capture = &alc260_pcm_analog_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007193
Takashi Iwaia3bcba32005-12-06 19:05:29 +01007194 spec->stream_digital_playback = &alc260_pcm_digital_playback;
7195 spec->stream_digital_capture = &alc260_pcm_digital_capture;
7196
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01007197 if (!spec->adc_nids && spec->input_mux) {
7198 /* check whether NID 0x04 is valid */
7199 unsigned int wcap = get_wcaps(codec, 0x04);
Takashi Iwaia22d5432009-07-27 12:54:26 +02007200 wcap = get_wcaps_type(wcap);
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01007201 /* get type */
7202 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
7203 spec->adc_nids = alc260_adc_nids_alt;
7204 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
7205 } else {
7206 spec->adc_nids = alc260_adc_nids;
7207 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
7208 }
7209 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02007210 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007211 set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007212
Takashi Iwaifc091762010-08-04 23:53:36 +02007213 if (board_config == ALC260_AUTO)
7214 alc_pick_fixup(codec, alc260_fixup_tbl, alc260_fixups, 0);
7215
Takashi Iwai2134ea42008-01-10 16:53:55 +01007216 spec->vmaster_nid = 0x08;
7217
Linus Torvalds1da177e2005-04-16 15:20:36 -07007218 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01007219 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007220 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02007221#ifdef CONFIG_SND_HDA_POWER_SAVE
7222 if (!spec->loopback.amplist)
7223 spec->loopback.amplist = alc260_loopbacks;
7224#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007225
7226 return 0;
7227}
7228
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007229
Linus Torvalds1da177e2005-04-16 15:20:36 -07007230/*
Takashi Iwai49535502009-06-30 15:28:30 +02007231 * ALC882/883/885/888/889 support
Linus Torvalds1da177e2005-04-16 15:20:36 -07007232 *
7233 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
7234 * configuration. Each pin widget can choose any input DACs and a mixer.
7235 * Each ADC is connected from a mixer of all inputs. This makes possible
7236 * 6-channel independent captures.
7237 *
7238 * In addition, an independent DAC for the multi-playback (not used in this
7239 * driver yet).
7240 */
Kailang Yangdf694da2005-12-05 19:42:22 +01007241#define ALC882_DIGOUT_NID 0x06
7242#define ALC882_DIGIN_NID 0x0a
Takashi Iwai49535502009-06-30 15:28:30 +02007243#define ALC883_DIGOUT_NID ALC882_DIGOUT_NID
7244#define ALC883_DIGIN_NID ALC882_DIGIN_NID
7245#define ALC1200_DIGOUT_NID 0x10
7246
Linus Torvalds1da177e2005-04-16 15:20:36 -07007247
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01007248static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007249 { 8, NULL }
7250};
7251
Takashi Iwai49535502009-06-30 15:28:30 +02007252/* DACs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007253static hda_nid_t alc882_dac_nids[4] = {
7254 /* front, rear, clfe, rear_surr */
7255 0x02, 0x03, 0x04, 0x05
7256};
Takashi Iwai49535502009-06-30 15:28:30 +02007257#define alc883_dac_nids alc882_dac_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007258
Takashi Iwai49535502009-06-30 15:28:30 +02007259/* ADCs */
Kailang Yangdf694da2005-12-05 19:42:22 +01007260#define alc882_adc_nids alc880_adc_nids
7261#define alc882_adc_nids_alt alc880_adc_nids_alt
Takashi Iwai49535502009-06-30 15:28:30 +02007262#define alc883_adc_nids alc882_adc_nids_alt
7263static hda_nid_t alc883_adc_nids_alt[1] = { 0x08 };
7264static hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 };
7265#define alc889_adc_nids alc880_adc_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007266
Takashi Iwaie1406342008-02-11 18:32:32 +01007267static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
7268static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
Takashi Iwai49535502009-06-30 15:28:30 +02007269#define alc883_capsrc_nids alc882_capsrc_nids_alt
7270static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
7271#define alc889_capsrc_nids alc882_capsrc_nids
Takashi Iwaie1406342008-02-11 18:32:32 +01007272
Linus Torvalds1da177e2005-04-16 15:20:36 -07007273/* input MUX */
7274/* FIXME: should be a matrix-type input source selection */
7275
7276static struct hda_input_mux alc882_capture_source = {
7277 .num_items = 4,
7278 .items = {
7279 { "Mic", 0x0 },
7280 { "Front Mic", 0x1 },
7281 { "Line", 0x2 },
7282 { "CD", 0x4 },
7283 },
7284};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007285
Takashi Iwai49535502009-06-30 15:28:30 +02007286#define alc883_capture_source alc882_capture_source
7287
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007288static struct hda_input_mux alc889_capture_source = {
7289 .num_items = 3,
7290 .items = {
7291 { "Front Mic", 0x0 },
7292 { "Mic", 0x3 },
7293 { "Line", 0x2 },
7294 },
7295};
7296
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007297static struct hda_input_mux mb5_capture_source = {
7298 .num_items = 3,
7299 .items = {
7300 { "Mic", 0x1 },
Alex Murrayb8f171e2010-06-14 12:08:43 +09307301 { "Line", 0x7 },
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007302 { "CD", 0x4 },
7303 },
7304};
7305
Luke Yelaviche458b1f2010-02-12 16:28:29 +11007306static struct hda_input_mux macmini3_capture_source = {
7307 .num_items = 2,
7308 .items = {
7309 { "Line", 0x2 },
7310 { "CD", 0x4 },
7311 },
7312};
7313
Takashi Iwai49535502009-06-30 15:28:30 +02007314static struct hda_input_mux alc883_3stack_6ch_intel = {
7315 .num_items = 4,
7316 .items = {
7317 { "Mic", 0x1 },
7318 { "Front Mic", 0x0 },
7319 { "Line", 0x2 },
7320 { "CD", 0x4 },
7321 },
7322};
7323
7324static struct hda_input_mux alc883_lenovo_101e_capture_source = {
7325 .num_items = 2,
7326 .items = {
7327 { "Mic", 0x1 },
7328 { "Line", 0x2 },
7329 },
7330};
7331
7332static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
7333 .num_items = 4,
7334 .items = {
7335 { "Mic", 0x0 },
David Henningsson150b4322010-07-29 14:46:42 +02007336 { "Int Mic", 0x1 },
Takashi Iwai49535502009-06-30 15:28:30 +02007337 { "Line", 0x2 },
7338 { "CD", 0x4 },
7339 },
7340};
7341
7342static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
7343 .num_items = 2,
7344 .items = {
7345 { "Mic", 0x0 },
7346 { "Int Mic", 0x1 },
7347 },
7348};
7349
7350static struct hda_input_mux alc883_lenovo_sky_capture_source = {
7351 .num_items = 3,
7352 .items = {
7353 { "Mic", 0x0 },
7354 { "Front Mic", 0x1 },
7355 { "Line", 0x4 },
7356 },
7357};
7358
7359static struct hda_input_mux alc883_asus_eee1601_capture_source = {
7360 .num_items = 2,
7361 .items = {
7362 { "Mic", 0x0 },
7363 { "Line", 0x2 },
7364 },
7365};
7366
7367static struct hda_input_mux alc889A_mb31_capture_source = {
7368 .num_items = 2,
7369 .items = {
7370 { "Mic", 0x0 },
7371 /* Front Mic (0x01) unused */
7372 { "Line", 0x2 },
7373 /* Line 2 (0x03) unused */
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02007374 /* CD (0x04) unused? */
Takashi Iwai49535502009-06-30 15:28:30 +02007375 },
7376};
7377
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07007378static struct hda_input_mux alc889A_imac91_capture_source = {
7379 .num_items = 2,
7380 .items = {
7381 { "Mic", 0x01 },
7382 { "Line", 0x2 }, /* Not sure! */
7383 },
7384};
7385
Takashi Iwai49535502009-06-30 15:28:30 +02007386/*
7387 * 2ch mode
7388 */
7389static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
7390 { 2, NULL }
7391};
7392
Kailang Yangdf694da2005-12-05 19:42:22 +01007393/*
Kailang Yang272a5272007-05-14 11:00:38 +02007394 * 2ch mode
7395 */
7396static struct hda_verb alc882_3ST_ch2_init[] = {
7397 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7398 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7399 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7400 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7401 { } /* end */
7402};
7403
7404/*
Takashi Iwai49535502009-06-30 15:28:30 +02007405 * 4ch mode
7406 */
7407static struct hda_verb alc882_3ST_ch4_init[] = {
7408 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7409 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7410 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7411 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7412 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7413 { } /* end */
7414};
7415
7416/*
Kailang Yang272a5272007-05-14 11:00:38 +02007417 * 6ch mode
7418 */
7419static struct hda_verb alc882_3ST_ch6_init[] = {
7420 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7421 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7422 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7423 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7424 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7425 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7426 { } /* end */
7427};
7428
Takashi Iwai49535502009-06-30 15:28:30 +02007429static struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
Kailang Yang272a5272007-05-14 11:00:38 +02007430 { 2, alc882_3ST_ch2_init },
Takashi Iwai49535502009-06-30 15:28:30 +02007431 { 4, alc882_3ST_ch4_init },
Kailang Yang272a5272007-05-14 11:00:38 +02007432 { 6, alc882_3ST_ch6_init },
7433};
7434
Takashi Iwai49535502009-06-30 15:28:30 +02007435#define alc883_3ST_6ch_modes alc882_3ST_6ch_modes
7436
Kailang Yang272a5272007-05-14 11:00:38 +02007437/*
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307438 * 2ch mode
7439 */
7440static struct hda_verb alc883_3ST_ch2_clevo_init[] = {
7441 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
7442 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7443 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7444 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7445 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7446 { } /* end */
7447};
7448
7449/*
7450 * 4ch mode
7451 */
7452static struct hda_verb alc883_3ST_ch4_clevo_init[] = {
7453 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7454 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7455 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7456 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7457 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7458 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7459 { } /* end */
7460};
7461
7462/*
7463 * 6ch mode
7464 */
7465static struct hda_verb alc883_3ST_ch6_clevo_init[] = {
7466 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7467 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7468 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7469 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7470 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7471 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7472 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7473 { } /* end */
7474};
7475
7476static struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
7477 { 2, alc883_3ST_ch2_clevo_init },
7478 { 4, alc883_3ST_ch4_clevo_init },
7479 { 6, alc883_3ST_ch6_clevo_init },
7480};
7481
7482
7483/*
Kailang Yangdf694da2005-12-05 19:42:22 +01007484 * 6ch mode
7485 */
7486static struct hda_verb alc882_sixstack_ch6_init[] = {
7487 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7488 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7489 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7490 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7491 { } /* end */
7492};
7493
7494/*
7495 * 8ch mode
7496 */
7497static struct hda_verb alc882_sixstack_ch8_init[] = {
7498 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7499 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7500 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7501 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7502 { } /* end */
7503};
7504
7505static struct hda_channel_mode alc882_sixstack_modes[2] = {
7506 { 6, alc882_sixstack_ch6_init },
7507 { 8, alc882_sixstack_ch8_init },
7508};
7509
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08007510
7511/* Macbook Air 2,1 */
7512
7513static struct hda_channel_mode alc885_mba21_ch_modes[1] = {
7514 { 2, NULL },
7515};
7516
Takashi Iwai87350ad2007-08-16 18:19:38 +02007517/*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04007518 * macbook pro ALC885 can switch LineIn to LineOut without losing Mic
Takashi Iwai87350ad2007-08-16 18:19:38 +02007519 */
7520
7521/*
7522 * 2ch mode
7523 */
7524static struct hda_verb alc885_mbp_ch2_init[] = {
7525 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7526 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7527 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7528 { } /* end */
7529};
7530
7531/*
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007532 * 4ch mode
Takashi Iwai87350ad2007-08-16 18:19:38 +02007533 */
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007534static struct hda_verb alc885_mbp_ch4_init[] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007535 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7536 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7537 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7538 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7539 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7540 { } /* end */
7541};
7542
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007543static struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007544 { 2, alc885_mbp_ch2_init },
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007545 { 4, alc885_mbp_ch4_init },
Takashi Iwai87350ad2007-08-16 18:19:38 +02007546};
7547
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007548/*
7549 * 2ch
7550 * Speakers/Woofer/HP = Front
7551 * LineIn = Input
7552 */
7553static struct hda_verb alc885_mb5_ch2_init[] = {
7554 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7555 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7556 { } /* end */
7557};
7558
7559/*
7560 * 6ch mode
7561 * Speakers/HP = Front
7562 * Woofer = LFE
7563 * LineIn = Surround
7564 */
7565static struct hda_verb alc885_mb5_ch6_init[] = {
7566 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7567 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7568 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7569 { } /* end */
7570};
7571
7572static struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
7573 { 2, alc885_mb5_ch2_init },
7574 { 6, alc885_mb5_ch6_init },
7575};
Takashi Iwai87350ad2007-08-16 18:19:38 +02007576
Takashi Iwaid01aecd2010-02-23 08:07:15 +01007577#define alc885_macmini3_6ch_modes alc885_mb5_6ch_modes
Takashi Iwai49535502009-06-30 15:28:30 +02007578
7579/*
7580 * 2ch mode
7581 */
7582static struct hda_verb alc883_4ST_ch2_init[] = {
7583 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7584 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7585 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7586 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7587 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7588 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7589 { } /* end */
7590};
7591
7592/*
7593 * 4ch mode
7594 */
7595static struct hda_verb alc883_4ST_ch4_init[] = {
7596 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7597 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7598 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7599 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7600 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7601 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7602 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7603 { } /* end */
7604};
7605
7606/*
7607 * 6ch mode
7608 */
7609static struct hda_verb alc883_4ST_ch6_init[] = {
7610 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7611 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7612 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7613 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7614 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7615 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7616 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7617 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7618 { } /* end */
7619};
7620
7621/*
7622 * 8ch mode
7623 */
7624static struct hda_verb alc883_4ST_ch8_init[] = {
7625 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7626 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7627 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7628 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7629 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7630 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7631 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7632 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7633 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7634 { } /* end */
7635};
7636
7637static struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
7638 { 2, alc883_4ST_ch2_init },
7639 { 4, alc883_4ST_ch4_init },
7640 { 6, alc883_4ST_ch6_init },
7641 { 8, alc883_4ST_ch8_init },
7642};
7643
7644
7645/*
7646 * 2ch mode
7647 */
7648static struct hda_verb alc883_3ST_ch2_intel_init[] = {
7649 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7650 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7651 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7652 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7653 { } /* end */
7654};
7655
7656/*
7657 * 4ch mode
7658 */
7659static struct hda_verb alc883_3ST_ch4_intel_init[] = {
7660 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7661 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7662 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7663 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7664 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7665 { } /* end */
7666};
7667
7668/*
7669 * 6ch mode
7670 */
7671static struct hda_verb alc883_3ST_ch6_intel_init[] = {
7672 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7673 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7674 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
7675 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7676 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7677 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7678 { } /* end */
7679};
7680
7681static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
7682 { 2, alc883_3ST_ch2_intel_init },
7683 { 4, alc883_3ST_ch4_intel_init },
7684 { 6, alc883_3ST_ch6_intel_init },
7685};
7686
7687/*
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007688 * 2ch mode
7689 */
7690static struct hda_verb alc889_ch2_intel_init[] = {
7691 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7692 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 },
7693 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 },
7694 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00 },
7695 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7696 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7697 { } /* end */
7698};
7699
7700/*
Takashi Iwai49535502009-06-30 15:28:30 +02007701 * 6ch mode
7702 */
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007703static struct hda_verb alc889_ch6_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007704 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7705 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7706 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7707 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7708 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007709 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7710 { } /* end */
7711};
7712
7713/*
7714 * 8ch mode
7715 */
7716static struct hda_verb alc889_ch8_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007717 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7718 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7719 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7720 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7721 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x03 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007722 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7723 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007724 { } /* end */
7725};
7726
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007727static struct hda_channel_mode alc889_8ch_intel_modes[3] = {
7728 { 2, alc889_ch2_intel_init },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007729 { 6, alc889_ch6_intel_init },
7730 { 8, alc889_ch8_intel_init },
7731};
7732
7733/*
7734 * 6ch mode
7735 */
Takashi Iwai49535502009-06-30 15:28:30 +02007736static struct hda_verb alc883_sixstack_ch6_init[] = {
7737 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7738 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7739 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7740 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7741 { } /* end */
7742};
7743
7744/*
7745 * 8ch mode
7746 */
7747static struct hda_verb alc883_sixstack_ch8_init[] = {
7748 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7749 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7750 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7751 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7752 { } /* end */
7753};
7754
7755static struct hda_channel_mode alc883_sixstack_modes[2] = {
7756 { 6, alc883_sixstack_ch6_init },
7757 { 8, alc883_sixstack_ch8_init },
7758};
7759
7760
Linus Torvalds1da177e2005-04-16 15:20:36 -07007761/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
7762 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
7763 */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01007764static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02007765 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007766 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007767 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007768 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007769 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7770 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007771 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7772 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007773 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007774 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007775 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7776 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7777 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7778 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7779 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7780 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007781 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007782 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7783 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007784 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007785 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007786 { } /* end */
7787};
7788
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08007789/* Macbook Air 2,1 same control for HP and internal Speaker */
7790
7791static struct snd_kcontrol_new alc885_mba21_mixer[] = {
7792 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7793 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT),
7794 { }
7795};
7796
7797
Takashi Iwai87350ad2007-08-16 18:19:38 +02007798static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007799 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7800 HDA_BIND_MUTE ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
7801 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7802 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT),
7803 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01007804 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7805 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02007806 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
7807 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01007808 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02007809 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
7810 { } /* end */
7811};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007812
7813static struct snd_kcontrol_new alc885_mb5_mixer[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007814 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7815 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
7816 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
7817 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
7818 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7819 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
Alex Murraya76221d2010-01-13 23:15:03 +10307820 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
7821 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
Alex Murrayb8f171e2010-06-14 12:08:43 +09307822 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
7823 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007824 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
7825 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
7826 HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT),
7827 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0x00, HDA_INPUT),
7828 { } /* end */
7829};
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007830
Luke Yelaviche458b1f2010-02-12 16:28:29 +11007831static struct snd_kcontrol_new alc885_macmini3_mixer[] = {
7832 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7833 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
7834 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
7835 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
7836 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7837 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
7838 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
7839 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
7840 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
7841 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
7842 HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT),
7843 { } /* end */
7844};
7845
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08007846static struct snd_kcontrol_new alc885_imac91_mixer[] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07007847 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7848 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08007849 { } /* end */
7850};
7851
7852
Kailang Yangbdd148a2007-05-08 15:19:08 +02007853static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
7854 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7855 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7856 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7857 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7858 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7859 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7860 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7861 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7862 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02007863 { } /* end */
7864};
7865
Kailang Yang272a5272007-05-14 11:00:38 +02007866static struct snd_kcontrol_new alc882_targa_mixer[] = {
7867 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7868 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7869 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7870 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7871 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7872 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7873 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7874 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7875 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02007876 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007877 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7878 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02007879 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007880 { } /* end */
7881};
7882
7883/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
7884 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
7885 */
7886static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
7887 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7888 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7889 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7890 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
7891 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7892 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7893 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7894 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7895 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
7896 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
7897 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7898 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02007899 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007900 { } /* end */
7901};
7902
Takashi Iwai914759b2007-09-06 14:52:04 +02007903static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
7904 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7905 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7906 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7907 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7908 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7909 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7910 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7911 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7912 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7913 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02007914 { } /* end */
7915};
7916
Kailang Yangdf694da2005-12-05 19:42:22 +01007917static struct snd_kcontrol_new alc882_chmode_mixer[] = {
7918 {
7919 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7920 .name = "Channel Mode",
7921 .info = alc_ch_mode_info,
7922 .get = alc_ch_mode_get,
7923 .put = alc_ch_mode_put,
7924 },
7925 { } /* end */
7926};
7927
Takashi Iwai49535502009-06-30 15:28:30 +02007928static struct hda_verb alc882_base_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007929 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007930 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7931 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007932 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02007933 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7934 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007935 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02007936 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7937 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007938 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02007939 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7940 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007941
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007942 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007943 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007944 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007945 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007946 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007947 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007948 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007949 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007950 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007951 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007952 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007953 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007954 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007955 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007956 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007957 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007958 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02007959 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007960 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7961 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02007962 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007963 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7964 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02007965 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007966 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7967 /* Line-2 In: Headphone output (output 0 - 0x0c) */
7968 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7969 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7970 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007971 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02007972 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007973
7974 /* FIXME: use matrix-type input source selection */
7975 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007976 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02007977 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007978 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02007979 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai05acb862005-06-10 19:50:25 +02007980 /* ADC2: mute amp left and right */
7981 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02007982 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02007983 /* ADC3: mute amp left and right */
7984 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02007985 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007986
7987 { }
7988};
7989
Takashi Iwai49535502009-06-30 15:28:30 +02007990static struct hda_verb alc882_adc1_init_verbs[] = {
7991 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
7992 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7993 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7994 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7995 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7996 /* ADC1: mute amp left and right */
7997 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7998 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
7999 { }
8000};
8001
Takashi Iwai4b146cb2006-07-28 14:42:36 +02008002static struct hda_verb alc882_eapd_verbs[] = {
8003 /* change to EAPD mode */
8004 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008005 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008006 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02008007};
8008
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008009static struct hda_verb alc889_eapd_verbs[] = {
8010 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
8011 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
8012 { }
8013};
8014
Wu Fengguang6732bd02009-07-30 09:19:14 +02008015static struct hda_verb alc_hp15_unsol_verbs[] = {
8016 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8017 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8018 {}
8019};
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008020
8021static struct hda_verb alc885_init_verbs[] = {
8022 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Kailang Yang88102f32010-02-04 14:12:58 +01008023 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8024 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008025 /* Rear mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008026 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8027 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008028 /* CLFE mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008029 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8030 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008031 /* Side mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008032 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8033 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008034
8035 /* Front HP Pin: output 0 (0x0c) */
Wu Fengguang6732bd02009-07-30 09:19:14 +02008036 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008037 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8038 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8039 /* Front Pin: output 0 (0x0c) */
8040 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8041 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8042 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8043 /* Rear Pin: output 1 (0x0d) */
8044 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8045 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8046 {0x19, AC_VERB_SET_CONNECT_SEL, 0x01},
8047 /* CLFE Pin: output 2 (0x0e) */
8048 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8049 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8050 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
8051 /* Side Pin: output 3 (0x0f) */
8052 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8053 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8054 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
8055 /* Mic (rear) pin: input vref at 80% */
8056 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8057 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8058 /* Front Mic pin: input vref at 80% */
8059 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8060 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8061 /* Line In pin: input */
8062 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8063 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8064
8065 /* Mixer elements: 0x18, , 0x1a, 0x1b */
8066 /* Input mixer1 */
Kailang Yang88102f32010-02-04 14:12:58 +01008067 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008068 /* Input mixer2 */
8069 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008070 /* Input mixer3 */
Kailang Yang88102f32010-02-04 14:12:58 +01008071 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008072 /* ADC2: mute amp left and right */
8073 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8074 /* ADC3: mute amp left and right */
8075 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8076
8077 { }
8078};
8079
8080static struct hda_verb alc885_init_input_verbs[] = {
8081 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8082 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
8083 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
8084 { }
8085};
8086
8087
8088/* Unmute Selector 24h and set the default input to front mic */
8089static struct hda_verb alc889_init_input_verbs[] = {
8090 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
8091 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8092 { }
8093};
8094
8095
Takashi Iwai49535502009-06-30 15:28:30 +02008096#define alc883_init_verbs alc882_base_init_verbs
8097
Tobin Davis9102cd12006-12-15 10:02:12 +01008098/* Mac Pro test */
8099static struct snd_kcontrol_new alc882_macpro_mixer[] = {
8100 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8101 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8102 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
8103 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
8104 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01008105 /* FIXME: this looks suspicious...
Jaroslav Kyselad355c82a2009-11-03 15:47:25 +01008106 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT),
8107 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01008108 */
Tobin Davis9102cd12006-12-15 10:02:12 +01008109 { } /* end */
8110};
8111
8112static struct hda_verb alc882_macpro_init_verbs[] = {
8113 /* Front mixer: unmute input/output amp left and right (volume = 0) */
8114 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8115 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8116 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8117 /* Front Pin: output 0 (0x0c) */
8118 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8119 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8120 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8121 /* Front Mic pin: input vref at 80% */
8122 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8123 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8124 /* Speaker: output */
8125 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8126 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8127 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
8128 /* Headphone output (output 0 - 0x0c) */
8129 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8130 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8131 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8132
8133 /* FIXME: use matrix-type input source selection */
8134 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8135 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8136 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8137 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8138 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8139 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8140 /* Input mixer2 */
8141 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8142 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8143 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8144 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8145 /* Input mixer3 */
8146 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8147 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8148 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8149 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8150 /* ADC1: mute amp left and right */
8151 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8152 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8153 /* ADC2: mute amp left and right */
8154 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8155 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8156 /* ADC3: mute amp left and right */
8157 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8158 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8159
8160 { }
8161};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008162
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008163/* Macbook 5,1 */
8164static struct hda_verb alc885_mb5_init_verbs[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008165 /* DACs */
8166 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8167 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8168 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8169 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008170 /* Front mixer */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008171 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8172 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8173 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008174 /* Surround mixer */
8175 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8176 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8177 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8178 /* LFE mixer */
8179 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8180 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8181 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8182 /* HP mixer */
8183 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8184 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8185 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8186 /* Front Pin (0x0c) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008187 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8188 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008189 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8190 /* LFE Pin (0x0e) */
8191 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8192 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8193 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
8194 /* HP Pin (0x0f) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008195 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8196 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008197 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
Alex Murraya76221d2010-01-13 23:15:03 +10308198 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008199 /* Front Mic pin: input vref at 80% */
8200 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8201 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8202 /* Line In pin */
8203 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8204 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8205
Alex Murrayb8f171e2010-06-14 12:08:43 +09308206 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0x1)},
8207 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x7)},
8208 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x4)},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008209 { }
8210};
8211
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008212/* Macmini 3,1 */
8213static struct hda_verb alc885_macmini3_init_verbs[] = {
8214 /* DACs */
8215 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8216 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8217 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8218 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8219 /* Front mixer */
8220 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8221 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8222 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8223 /* Surround mixer */
8224 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8225 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8226 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8227 /* LFE mixer */
8228 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8229 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8230 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8231 /* HP mixer */
8232 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8233 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8234 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8235 /* Front Pin (0x0c) */
8236 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8237 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8238 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8239 /* LFE Pin (0x0e) */
8240 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8241 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8242 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
8243 /* HP Pin (0x0f) */
8244 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8245 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8246 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
8247 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8248 /* Line In pin */
8249 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8250 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8251
8252 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8253 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8254 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8255 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8256 { }
8257};
8258
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008259
8260static struct hda_verb alc885_mba21_init_verbs[] = {
8261 /*Internal and HP Speaker Mixer*/
8262 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8263 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8264 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8265 /*Internal Speaker Pin (0x0c)*/
8266 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8267 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8268 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8269 /* HP Pin: output 0 (0x0e) */
8270 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
8271 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8272 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8273 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
8274 /* Line in (is hp when jack connected)*/
8275 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
8276 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8277
8278 { }
8279 };
8280
8281
Takashi Iwai87350ad2007-08-16 18:19:38 +02008282/* Macbook Pro rev3 */
8283static struct hda_verb alc885_mbp3_init_verbs[] = {
8284 /* Front mixer: unmute input/output amp left and right (volume = 0) */
8285 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8286 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8287 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8288 /* Rear mixer */
8289 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8290 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8291 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008292 /* HP mixer */
8293 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8294 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8295 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai87350ad2007-08-16 18:19:38 +02008296 /* Front Pin: output 0 (0x0c) */
8297 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8298 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8299 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008300 /* HP Pin: output 0 (0x0e) */
Takashi Iwai87350ad2007-08-16 18:19:38 +02008301 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008302 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8303 {0x15, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai87350ad2007-08-16 18:19:38 +02008304 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8305 /* Mic (rear) pin: input vref at 80% */
8306 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8307 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8308 /* Front Mic pin: input vref at 80% */
8309 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8310 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8311 /* Line In pin: use output 1 when in LineOut mode */
8312 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8313 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8314 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
8315
8316 /* FIXME: use matrix-type input source selection */
8317 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8318 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8319 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8320 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8321 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8322 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8323 /* Input mixer2 */
8324 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8325 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8326 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8327 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8328 /* Input mixer3 */
8329 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8330 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8331 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8332 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8333 /* ADC1: mute amp left and right */
8334 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8335 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8336 /* ADC2: mute amp left and right */
8337 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8338 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8339 /* ADC3: mute amp left and right */
8340 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8341 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8342
8343 { }
8344};
8345
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008346/* iMac 9,1 */
8347static struct hda_verb alc885_imac91_init_verbs[] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008348 /* Internal Speaker Pin (0x0c) */
8349 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8350 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8351 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8352 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8353 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8354 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8355 /* HP Pin: Rear */
8356 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8357 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8358 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8359 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
8360 /* Line in Rear */
8361 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
8362 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8363 /* Front Mic pin: input vref at 80% */
8364 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8365 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008366 /* Rear mixer */
8367 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8368 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8369 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008370 /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */
8371 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8372 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8373 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8374 /* 0x24 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008375 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8376 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8377 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8378 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008379 /* 0x23 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008380 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8381 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8382 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8383 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008384 /* 0x22 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008385 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8386 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8387 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8388 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008389 /* 0x07 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008390 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8391 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008392 /* 0x08 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008393 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8394 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008395 /* 0x09 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008396 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8397 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008398 { }
8399};
8400
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008401/* iMac 24 mixer. */
8402static struct snd_kcontrol_new alc885_imac24_mixer[] = {
8403 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8404 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
8405 { } /* end */
8406};
8407
8408/* iMac 24 init verbs. */
8409static struct hda_verb alc885_imac24_init_verbs[] = {
8410 /* Internal speakers: output 0 (0x0c) */
8411 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8412 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8413 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8414 /* Internal speakers: output 0 (0x0c) */
8415 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8416 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8417 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8418 /* Headphone: output 0 (0x0c) */
8419 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8420 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8421 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8422 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8423 /* Front Mic: input vref at 80% */
8424 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8425 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8426 { }
8427};
8428
8429/* Toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008430static void alc885_imac24_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008431{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008432 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008433
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008434 spec->autocfg.hp_pins[0] = 0x14;
8435 spec->autocfg.speaker_pins[0] = 0x18;
8436 spec->autocfg.speaker_pins[1] = 0x1a;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008437}
8438
Takashi Iwai9d54f082010-02-22 08:34:40 +01008439#define alc885_mb5_setup alc885_imac24_setup
8440#define alc885_macmini3_setup alc885_imac24_setup
8441
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008442/* Macbook Air 2,1 */
8443static void alc885_mba21_setup(struct hda_codec *codec)
8444{
8445 struct alc_spec *spec = codec->spec;
8446
8447 spec->autocfg.hp_pins[0] = 0x14;
8448 spec->autocfg.speaker_pins[0] = 0x18;
8449}
8450
8451
8452
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008453static void alc885_mbp3_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008454{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008455 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008456
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008457 spec->autocfg.hp_pins[0] = 0x15;
8458 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai87350ad2007-08-16 18:19:38 +02008459}
8460
Takashi Iwai9d54f082010-02-22 08:34:40 +01008461static void alc885_imac91_setup(struct hda_codec *codec)
Alex Murraya76221d2010-01-13 23:15:03 +10308462{
Takashi Iwai9d54f082010-02-22 08:34:40 +01008463 struct alc_spec *spec = codec->spec;
Alex Murraya76221d2010-01-13 23:15:03 +10308464
Takashi Iwai9d54f082010-02-22 08:34:40 +01008465 spec->autocfg.hp_pins[0] = 0x14;
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008466 spec->autocfg.speaker_pins[0] = 0x18;
Takashi Iwai9d54f082010-02-22 08:34:40 +01008467 spec->autocfg.speaker_pins[1] = 0x1a;
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008468}
Takashi Iwai87350ad2007-08-16 18:19:38 +02008469
Kailang Yang272a5272007-05-14 11:00:38 +02008470static struct hda_verb alc882_targa_verbs[] = {
8471 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8472 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8473
8474 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8475 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008476
Kailang Yang272a5272007-05-14 11:00:38 +02008477 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8478 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8479 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8480
8481 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yang272a5272007-05-14 11:00:38 +02008482 { } /* end */
8483};
8484
8485/* toggle speaker-output according to the hp-jack state */
8486static void alc882_targa_automute(struct hda_codec *codec)
8487{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008488 struct alc_spec *spec = codec->spec;
8489 alc_automute_amp(codec);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02008490 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008491 spec->jack_present ? 1 : 3);
8492}
8493
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008494static void alc882_targa_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008495{
8496 struct alc_spec *spec = codec->spec;
8497
8498 spec->autocfg.hp_pins[0] = 0x14;
8499 spec->autocfg.speaker_pins[0] = 0x1b;
Kailang Yang272a5272007-05-14 11:00:38 +02008500}
8501
8502static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
8503{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008504 if ((res >> 26) == ALC880_HP_EVENT)
Kailang Yang272a5272007-05-14 11:00:38 +02008505 alc882_targa_automute(codec);
Kailang Yang272a5272007-05-14 11:00:38 +02008506}
8507
8508static struct hda_verb alc882_asus_a7j_verbs[] = {
8509 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8510 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8511
8512 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8513 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8514 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008515
Kailang Yang272a5272007-05-14 11:00:38 +02008516 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8517 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8518 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8519
8520 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8521 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8522 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8523 { } /* end */
8524};
8525
Takashi Iwai914759b2007-09-06 14:52:04 +02008526static struct hda_verb alc882_asus_a7m_verbs[] = {
8527 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8528 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8529
8530 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8531 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8532 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008533
Takashi Iwai914759b2007-09-06 14:52:04 +02008534 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8535 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8536 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8537
8538 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8539 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8540 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8541 { } /* end */
8542};
8543
Tobin Davis9102cd12006-12-15 10:02:12 +01008544static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
8545{
8546 unsigned int gpiostate, gpiomask, gpiodir;
8547
8548 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
8549 AC_VERB_GET_GPIO_DATA, 0);
8550
8551 if (!muted)
8552 gpiostate |= (1 << pin);
8553 else
8554 gpiostate &= ~(1 << pin);
8555
8556 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
8557 AC_VERB_GET_GPIO_MASK, 0);
8558 gpiomask |= (1 << pin);
8559
8560 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
8561 AC_VERB_GET_GPIO_DIRECTION, 0);
8562 gpiodir |= (1 << pin);
8563
8564
8565 snd_hda_codec_write(codec, codec->afg, 0,
8566 AC_VERB_SET_GPIO_MASK, gpiomask);
8567 snd_hda_codec_write(codec, codec->afg, 0,
8568 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
8569
8570 msleep(1);
8571
8572 snd_hda_codec_write(codec, codec->afg, 0,
8573 AC_VERB_SET_GPIO_DATA, gpiostate);
8574}
8575
Takashi Iwai7debbe52007-08-16 15:01:03 +02008576/* set up GPIO at initialization */
8577static void alc885_macpro_init_hook(struct hda_codec *codec)
8578{
8579 alc882_gpio_mute(codec, 0, 0);
8580 alc882_gpio_mute(codec, 1, 0);
8581}
8582
8583/* set up GPIO and update auto-muting at initialization */
8584static void alc885_imac24_init_hook(struct hda_codec *codec)
8585{
8586 alc885_macpro_init_hook(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008587 alc_automute_amp(codec);
Takashi Iwai7debbe52007-08-16 15:01:03 +02008588}
8589
Kailang Yangdf694da2005-12-05 19:42:22 +01008590/*
8591 * generic initialization of ADC, input mixers and output mixers
8592 */
Takashi Iwai49535502009-06-30 15:28:30 +02008593static struct hda_verb alc883_auto_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01008594 /*
8595 * Unmute ADC0-2 and set the default input to mic-in
8596 */
Kailang Yangdf694da2005-12-05 19:42:22 +01008597 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8598 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8599 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8600 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8601
Kailang Yangdf694da2005-12-05 19:42:22 +01008602 /*
8603 * Set up output mixers (0x0c - 0x0f)
8604 */
8605 /* set vol=0 to output mixers */
8606 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8607 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8608 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8609 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8610 /* set up input amps for analog loopback */
8611 /* Amp Indices: DAC = 0, mixer = 1 */
8612 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8613 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8614 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8615 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8616 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8617 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8618 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8619 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8620 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8621 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8622
8623 /* FIXME: use matrix-type input source selection */
8624 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Kailang Yangdf694da2005-12-05 19:42:22 +01008625 /* Input mixer2 */
Kailang Yang88102f32010-02-04 14:12:58 +01008626 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008627 /* Input mixer3 */
Kailang Yang88102f32010-02-04 14:12:58 +01008628 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008629 { }
8630};
8631
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008632/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
8633static struct hda_verb alc889A_mb31_ch2_init[] = {
8634 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
8635 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8636 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
8637 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
8638 { } /* end */
8639};
8640
8641/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */
8642static struct hda_verb alc889A_mb31_ch4_init[] = {
8643 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
8644 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8645 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
8646 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
8647 { } /* end */
8648};
8649
8650/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */
8651static struct hda_verb alc889A_mb31_ch5_init[] = {
8652 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */
8653 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8654 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
8655 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
8656 { } /* end */
8657};
8658
8659/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */
8660static struct hda_verb alc889A_mb31_ch6_init[] = {
8661 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */
8662 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */
8663 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
8664 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
8665 { } /* end */
8666};
8667
8668static struct hda_channel_mode alc889A_mb31_6ch_modes[4] = {
8669 { 2, alc889A_mb31_ch2_init },
8670 { 4, alc889A_mb31_ch4_init },
8671 { 5, alc889A_mb31_ch5_init },
8672 { 6, alc889A_mb31_ch6_init },
8673};
8674
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008675static struct hda_verb alc883_medion_eapd_verbs[] = {
8676 /* eanable EAPD on medion laptop */
8677 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8678 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
8679 { }
8680};
8681
Takashi Iwai49535502009-06-30 15:28:30 +02008682#define alc883_base_mixer alc882_base_mixer
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008683
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008684static struct snd_kcontrol_new alc883_mitac_mixer[] = {
8685 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8686 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8687 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8688 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8689 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8690 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8691 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8692 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8693 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8694 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8695 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8696 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
8697 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008698 { } /* end */
8699};
8700
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008701static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01008702 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8703 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8704 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8705 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8706 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8707 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8708 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8709 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8710 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8711 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01008712 { } /* end */
8713};
8714
Jiang zhefb97dc62008-03-06 11:07:11 +01008715static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
8716 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8717 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8718 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8719 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8720 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8721 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8722 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8723 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8724 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8725 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01008726 { } /* end */
8727};
8728
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008729static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
8730 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8731 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8732 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8733 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8734 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8735 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8736 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8737 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008738 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008739 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8740 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008741 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008742 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008743 { } /* end */
8744};
8745
8746static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
8747 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8748 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8749 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8750 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8751 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8752 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8753 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8754 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8755 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8756 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8757 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8758 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8759 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8760 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008761 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008762 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8763 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008764 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008765 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008766 { } /* end */
8767};
8768
Jiang zhe17bba1b2008-06-04 12:11:07 +02008769static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
8770 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8771 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8772 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8773 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8774 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
8775 HDA_OUTPUT),
8776 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8777 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8778 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8779 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8780 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8781 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8782 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8783 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8784 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8785 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
8786 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8787 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8788 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
8789 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008790 { } /* end */
8791};
8792
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008793static struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
8794 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8795 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8796 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8797 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8798 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
8799 HDA_OUTPUT),
8800 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8801 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8802 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8803 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8804 HDA_BIND_MUTE("Speaker Playback Switch", 0x0f, 2, HDA_INPUT),
8805 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8806 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8807 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8808 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
8809 HDA_CODEC_VOLUME("Mic Boost", 0x1b, 0, HDA_INPUT),
8810 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
8811 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8812 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
8813 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8814 { } /* end */
8815};
8816
Takashi Iwaid1d985f2006-11-23 19:27:12 +01008817static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02008818 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008819 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008820 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008821 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008822 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8823 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008824 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8825 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008826 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8827 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8828 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8829 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8830 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8831 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008832 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008833 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8834 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008835 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008836 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008837 { } /* end */
8838};
8839
Sasha Alexandrc2592492009-06-16 14:52:54 -04008840static struct snd_kcontrol_new alc883_targa_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02008841 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008842 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008843 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008844 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008845 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8846 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8847 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8848 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8849 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8850 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8851 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8852 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8853 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8854 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8855 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008856 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008857 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008858 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008859};
Kailang Yangccc656c2006-10-17 12:32:26 +02008860
Sasha Alexandrc2592492009-06-16 14:52:54 -04008861static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02008862 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008863 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008864 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008865 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008866 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8867 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8868 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008869 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008870 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe4383fae2008-04-14 12:58:57 +02008871 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8872 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8873 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008874 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008875};
Kailang Yangccc656c2006-10-17 12:32:26 +02008876
Takashi Iwaib99dba32009-09-17 18:23:00 +02008877static struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
8878 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8879 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
8880 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8881 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8882 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8883 { } /* end */
8884};
8885
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008886static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
8887 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8888 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01008889 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8890 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008891 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8892 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8893 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8894 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008895 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008896};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008897
Kailang Yang272a5272007-05-14 11:00:38 +02008898static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
8899 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8900 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
8901 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8902 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8903 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8904 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8905 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson150b4322010-07-29 14:46:42 +02008906 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8907 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008908 { } /* end */
8909};
8910
8911static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
8912 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8913 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8914 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8915 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8916 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8917 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8918 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8919 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8920 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008921 { } /* end */
Kailang Yangea1fb292008-08-26 12:58:38 +02008922};
Kailang Yang272a5272007-05-14 11:00:38 +02008923
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02008924static struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = {
8925 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8926 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8927 HDA_CODEC_MUTE("Speaker Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8928 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
8929 HDA_CODEC_VOLUME("Line Playback Volume", 0x08, 0x0, HDA_INPUT),
8930 HDA_CODEC_MUTE("Line Playback Switch", 0x08, 0x0, HDA_INPUT),
8931 { } /* end */
8932};
8933
8934static struct hda_verb alc883_medion_wim2160_verbs[] = {
8935 /* Unmute front mixer */
8936 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8937 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8938
8939 /* Set speaker pin to front mixer */
8940 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8941
8942 /* Init headphone pin */
8943 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8944 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8945 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8946 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8947
8948 { } /* end */
8949};
8950
8951/* toggle speaker-output according to the hp-jack state */
8952static void alc883_medion_wim2160_setup(struct hda_codec *codec)
8953{
8954 struct alc_spec *spec = codec->spec;
8955
8956 spec->autocfg.hp_pins[0] = 0x1a;
8957 spec->autocfg.speaker_pins[0] = 0x15;
8958}
8959
Tobin Davis2880a862007-08-07 11:50:26 +02008960static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02008961 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8962 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02008963 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02008964 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8965 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02008966 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8967 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8968 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02008969 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02008970};
Tobin Davis2880a862007-08-07 11:50:26 +02008971
Tony Vroond2fd4b02009-06-21 00:40:10 +01008972static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
8973 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01008974 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Tony Vroon684a8842009-06-26 09:27:50 +01008975 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8976 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01008977 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8978 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8979 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8980 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8981 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8982 { } /* end */
8983};
8984
Kailang Yange2757d52008-08-26 13:17:46 +02008985static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
8986 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8987 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8988 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
8989 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
8990 HDA_CODEC_VOLUME_MONO("Center Playback Volume",
8991 0x0d, 1, 0x0, HDA_OUTPUT),
8992 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
8993 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
8994 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
8995 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8996 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02008997 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8998 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8999 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9000 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9001 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9002 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9003 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9004 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
9005 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
9006 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009007 { } /* end */
9008};
9009
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009010static struct snd_kcontrol_new alc889A_mb31_mixer[] = {
9011 /* Output mixers */
9012 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
9013 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
9014 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
9015 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
9016 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00,
9017 HDA_OUTPUT),
9018 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT),
9019 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT),
9020 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT),
9021 /* Output switches */
9022 HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT),
9023 HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT),
9024 HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT),
9025 /* Boost mixers */
9026 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
9027 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
9028 /* Input mixers */
9029 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
9030 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
9031 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9032 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9033 { } /* end */
9034};
9035
Guido Günther3e1647c2009-06-05 00:47:26 +02009036static struct snd_kcontrol_new alc883_vaiott_mixer[] = {
9037 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9038 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9039 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9040 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
9041 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
9042 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
9043 { } /* end */
9044};
9045
Kailang Yange2757d52008-08-26 13:17:46 +02009046static struct hda_bind_ctls alc883_bind_cap_vol = {
9047 .ops = &snd_hda_bind_vol,
9048 .values = {
9049 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
9050 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
9051 0
9052 },
9053};
9054
9055static struct hda_bind_ctls alc883_bind_cap_switch = {
9056 .ops = &snd_hda_bind_sw,
9057 .values = {
9058 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
9059 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
9060 0
9061 },
9062};
9063
9064static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
9065 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9066 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9067 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9068 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9069 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9070 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9071 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9072 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009073 { } /* end */
9074};
9075
9076static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009077 HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
9078 HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
9079 {
9080 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9081 /* .name = "Capture Source", */
9082 .name = "Input Source",
9083 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01009084 .info = alc_mux_enum_info,
9085 .get = alc_mux_enum_get,
9086 .put = alc_mux_enum_put,
Kailang Yange2757d52008-08-26 13:17:46 +02009087 },
9088 { } /* end */
9089};
9090
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009091static struct snd_kcontrol_new alc883_chmode_mixer[] = {
9092 {
9093 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9094 .name = "Channel Mode",
9095 .info = alc_ch_mode_info,
9096 .get = alc_ch_mode_get,
9097 .put = alc_ch_mode_put,
9098 },
9099 { } /* end */
9100};
9101
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009102/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009103static void alc883_mitac_setup(struct hda_codec *codec)
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009104{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009105 struct alc_spec *spec = codec->spec;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009106
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009107 spec->autocfg.hp_pins[0] = 0x15;
9108 spec->autocfg.speaker_pins[0] = 0x14;
9109 spec->autocfg.speaker_pins[1] = 0x17;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009110}
9111
9112/* auto-toggle front mic */
9113/*
9114static void alc883_mitac_mic_automute(struct hda_codec *codec)
9115{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009116 unsigned char bits = snd_hda_jack_detect(codec, 0x18) ? HDA_AMP_MUTE : 0;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009117
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009118 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
9119}
9120*/
9121
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009122static struct hda_verb alc883_mitac_verbs[] = {
9123 /* HP */
9124 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9125 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9126 /* Subwoofer */
9127 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
9128 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9129
9130 /* enable unsolicited event */
9131 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9132 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
9133
9134 { } /* end */
9135};
9136
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309137static struct hda_verb alc883_clevo_m540r_verbs[] = {
9138 /* HP */
9139 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9140 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9141 /* Int speaker */
9142 /*{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},*/
9143
9144 /* enable unsolicited event */
9145 /*
9146 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9147 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
9148 */
9149
9150 { } /* end */
9151};
9152
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009153static struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01009154 /* HP */
9155 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9156 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9157 /* Int speaker */
9158 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
9159 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9160
9161 /* enable unsolicited event */
9162 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009163 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01009164
9165 { } /* end */
9166};
9167
Jiang zhefb97dc62008-03-06 11:07:11 +01009168static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
9169 /* HP */
9170 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9171 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9172 /* Subwoofer */
9173 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
9174 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9175
9176 /* enable unsolicited event */
9177 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9178
9179 { } /* end */
9180};
9181
Sasha Alexandrc2592492009-06-16 14:52:54 -04009182static struct hda_verb alc883_targa_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02009183 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9184 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9185
9186 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9187 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02009188
David Heidelberger64a8be72009-06-08 16:15:18 +02009189/* Connect Line-Out side jack (SPDIF) to Side */
9190 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9191 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9192 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
9193/* Connect Mic jack to CLFE */
9194 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9195 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9196 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
9197/* Connect Line-in jack to Surround */
9198 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9199 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9200 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
9201/* Connect HP out jack to Front */
9202 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9203 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9204 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangccc656c2006-10-17 12:32:26 +02009205
9206 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangccc656c2006-10-17 12:32:26 +02009207
9208 { } /* end */
9209};
9210
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009211static struct hda_verb alc883_lenovo_101e_verbs[] = {
9212 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9213 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
9214 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
9215 { } /* end */
9216};
9217
Kailang Yang272a5272007-05-14 11:00:38 +02009218static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
9219 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9220 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9221 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9222 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9223 { } /* end */
9224};
9225
9226static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
9227 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9228 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9229 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9230 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
9231 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9232 { } /* end */
9233};
9234
Kailang Yang189609a2007-08-20 11:31:23 +02009235static struct hda_verb alc883_haier_w66_verbs[] = {
9236 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9237 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9238
9239 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9240
9241 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9242 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9243 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9244 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9245 { } /* end */
9246};
9247
Kailang Yange2757d52008-08-26 13:17:46 +02009248static struct hda_verb alc888_lenovo_sky_verbs[] = {
9249 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9250 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9251 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9252 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9253 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9254 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9255 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
9256 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9257 { } /* end */
9258};
9259
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009260static struct hda_verb alc888_6st_dell_verbs[] = {
9261 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9262 { }
9263};
9264
Guido Günther3e1647c2009-06-05 00:47:26 +02009265static struct hda_verb alc883_vaiott_verbs[] = {
9266 /* HP */
9267 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9268 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9269
9270 /* enable unsolicited event */
9271 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9272
9273 { } /* end */
9274};
9275
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009276static void alc888_3st_hp_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009277{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009278 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009279
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009280 spec->autocfg.hp_pins[0] = 0x1b;
9281 spec->autocfg.speaker_pins[0] = 0x14;
9282 spec->autocfg.speaker_pins[1] = 0x16;
9283 spec->autocfg.speaker_pins[2] = 0x18;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009284}
9285
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009286static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009287 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01009288 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
9289 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009290 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009291 { } /* end */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009292};
9293
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009294/*
9295 * 2ch mode
9296 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009297static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009298 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9299 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9300 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
9301 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009302 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009303};
9304
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009305/*
9306 * 4ch mode
9307 */
9308static struct hda_verb alc888_3st_hp_4ch_init[] = {
9309 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9310 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9311 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9312 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9313 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
9314 { } /* end */
9315};
9316
9317/*
9318 * 6ch mode
9319 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009320static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009321 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9322 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009323 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009324 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9325 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009326 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
9327 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009328};
9329
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009330static struct hda_channel_mode alc888_3st_hp_modes[3] = {
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009331 { 2, alc888_3st_hp_2ch_init },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009332 { 4, alc888_3st_hp_4ch_init },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009333 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009334};
9335
Kailang Yang272a5272007-05-14 11:00:38 +02009336/* toggle front-jack and RCA according to the hp-jack state */
9337static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
9338{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009339 unsigned int present = snd_hda_jack_detect(codec, 0x1b);
Kailang Yangea1fb292008-08-26 12:58:38 +02009340
Takashi Iwai47fd8302007-08-10 17:11:07 +02009341 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9342 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9343 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9344 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02009345}
9346
9347/* toggle RCA according to the front-jack state */
9348static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
9349{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009350 unsigned int present = snd_hda_jack_detect(codec, 0x14);
Kailang Yangea1fb292008-08-26 12:58:38 +02009351
Takashi Iwai47fd8302007-08-10 17:11:07 +02009352 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9353 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02009354}
Takashi Iwai47fd8302007-08-10 17:11:07 +02009355
Kailang Yang272a5272007-05-14 11:00:38 +02009356static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
9357 unsigned int res)
9358{
9359 if ((res >> 26) == ALC880_HP_EVENT)
9360 alc888_lenovo_ms7195_front_automute(codec);
9361 if ((res >> 26) == ALC880_FRONT_EVENT)
9362 alc888_lenovo_ms7195_rca_automute(codec);
9363}
9364
9365static struct hda_verb alc883_medion_md2_verbs[] = {
9366 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9367 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9368
9369 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9370
9371 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9372 { } /* end */
9373};
9374
9375/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009376static void alc883_medion_md2_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +02009377{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009378 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009379
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009380 spec->autocfg.hp_pins[0] = 0x14;
9381 spec->autocfg.speaker_pins[0] = 0x15;
Kailang Yang272a5272007-05-14 11:00:38 +02009382}
9383
Kailang Yangccc656c2006-10-17 12:32:26 +02009384/* toggle speaker-output according to the hp-jack state */
Sasha Alexandrc2592492009-06-16 14:52:54 -04009385#define alc883_targa_init_hook alc882_targa_init_hook
9386#define alc883_targa_unsol_event alc882_targa_unsol_event
Jiang zhe368c7a92008-03-04 11:20:33 +01009387
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009388static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
9389{
9390 unsigned int present;
9391
Takashi Iwaid56757a2009-11-18 08:00:14 +01009392 present = snd_hda_jack_detect(codec, 0x18);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009393 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
9394 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9395}
9396
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009397static void alc883_clevo_m720_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009398{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009399 struct alc_spec *spec = codec->spec;
9400
9401 spec->autocfg.hp_pins[0] = 0x15;
9402 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009403}
9404
9405static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
9406{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009407 alc_automute_amp(codec);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009408 alc883_clevo_m720_mic_automute(codec);
9409}
9410
9411static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01009412 unsigned int res)
9413{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009414 switch (res >> 26) {
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009415 case ALC880_MIC_EVENT:
9416 alc883_clevo_m720_mic_automute(codec);
9417 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009418 default:
9419 alc_automute_amp_unsol_event(codec, res);
9420 break;
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009421 }
Jiang zhe368c7a92008-03-04 11:20:33 +01009422}
9423
Jiang zhefb97dc62008-03-06 11:07:11 +01009424/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009425static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01009426{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009427 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01009428
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009429 spec->autocfg.hp_pins[0] = 0x14;
9430 spec->autocfg.speaker_pins[0] = 0x15;
Jiang zhefb97dc62008-03-06 11:07:11 +01009431}
9432
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009433static void alc883_haier_w66_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01009434{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009435 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01009436
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009437 spec->autocfg.hp_pins[0] = 0x1b;
9438 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang189609a2007-08-20 11:31:23 +02009439}
9440
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009441static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
9442{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009443 int bits = snd_hda_jack_detect(codec, 0x14) ? HDA_AMP_MUTE : 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009444
Takashi Iwai47fd8302007-08-10 17:11:07 +02009445 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9446 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009447}
9448
9449static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
9450{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009451 int bits = snd_hda_jack_detect(codec, 0x1b) ? HDA_AMP_MUTE : 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009452
Takashi Iwai47fd8302007-08-10 17:11:07 +02009453 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9454 HDA_AMP_MUTE, bits);
9455 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9456 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009457}
9458
9459static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
9460 unsigned int res)
9461{
9462 if ((res >> 26) == ALC880_HP_EVENT)
9463 alc883_lenovo_101e_all_automute(codec);
9464 if ((res >> 26) == ALC880_FRONT_EVENT)
9465 alc883_lenovo_101e_ispeaker_automute(codec);
9466}
9467
Takashi Iwai676a9b52007-08-16 15:23:35 +02009468/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009469static void alc883_acer_aspire_setup(struct hda_codec *codec)
Takashi Iwai676a9b52007-08-16 15:23:35 +02009470{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009471 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009472
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009473 spec->autocfg.hp_pins[0] = 0x14;
9474 spec->autocfg.speaker_pins[0] = 0x15;
9475 spec->autocfg.speaker_pins[1] = 0x16;
Takashi Iwai676a9b52007-08-16 15:23:35 +02009476}
9477
Kailang Yangd1a991a2007-08-15 16:21:59 +02009478static struct hda_verb alc883_acer_eapd_verbs[] = {
9479 /* HP Pin: output 0 (0x0c) */
9480 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9481 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9482 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9483 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02009484 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9485 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009486 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009487 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
9488 /* eanable EAPD on medion laptop */
9489 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
9490 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02009491 /* enable unsolicited event */
9492 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009493 { }
9494};
9495
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009496static struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
9497 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9498 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
9499 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9500 { } /* end */
9501};
9502
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009503static void alc888_6st_dell_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009504{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009505 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009506
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009507 spec->autocfg.hp_pins[0] = 0x1b;
9508 spec->autocfg.speaker_pins[0] = 0x14;
9509 spec->autocfg.speaker_pins[1] = 0x15;
9510 spec->autocfg.speaker_pins[2] = 0x16;
9511 spec->autocfg.speaker_pins[3] = 0x17;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009512}
9513
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009514static void alc888_lenovo_sky_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009515{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009516 struct alc_spec *spec = codec->spec;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009517
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009518 spec->autocfg.hp_pins[0] = 0x1b;
9519 spec->autocfg.speaker_pins[0] = 0x14;
9520 spec->autocfg.speaker_pins[1] = 0x15;
9521 spec->autocfg.speaker_pins[2] = 0x16;
9522 spec->autocfg.speaker_pins[3] = 0x17;
9523 spec->autocfg.speaker_pins[4] = 0x1a;
Kailang Yange2757d52008-08-26 13:17:46 +02009524}
9525
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009526static void alc883_vaiott_setup(struct hda_codec *codec)
Guido Günther3e1647c2009-06-05 00:47:26 +02009527{
9528 struct alc_spec *spec = codec->spec;
9529
9530 spec->autocfg.hp_pins[0] = 0x15;
9531 spec->autocfg.speaker_pins[0] = 0x14;
9532 spec->autocfg.speaker_pins[1] = 0x17;
Guido Günther3e1647c2009-06-05 00:47:26 +02009533}
9534
Kailang Yange2757d52008-08-26 13:17:46 +02009535static struct hda_verb alc888_asus_m90v_verbs[] = {
9536 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9537 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9538 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9539 /* enable unsolicited event */
9540 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9541 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
9542 { } /* end */
9543};
9544
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009545static void alc883_mode2_setup(struct hda_codec *codec)
Kailang Yange2757d52008-08-26 13:17:46 +02009546{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009547 struct alc_spec *spec = codec->spec;
Kailang Yange2757d52008-08-26 13:17:46 +02009548
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009549 spec->autocfg.hp_pins[0] = 0x1b;
9550 spec->autocfg.speaker_pins[0] = 0x14;
9551 spec->autocfg.speaker_pins[1] = 0x15;
9552 spec->autocfg.speaker_pins[2] = 0x16;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009553 spec->ext_mic.pin = 0x18;
9554 spec->int_mic.pin = 0x19;
9555 spec->ext_mic.mux_idx = 0;
9556 spec->int_mic.mux_idx = 1;
9557 spec->auto_mic = 1;
Kailang Yange2757d52008-08-26 13:17:46 +02009558}
9559
9560static struct hda_verb alc888_asus_eee1601_verbs[] = {
9561 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9562 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9563 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9564 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9565 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9566 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
9567 {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
9568 /* enable unsolicited event */
9569 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9570 { } /* end */
9571};
9572
Kailang Yange2757d52008-08-26 13:17:46 +02009573static void alc883_eee1601_inithook(struct hda_codec *codec)
9574{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009575 struct alc_spec *spec = codec->spec;
9576
9577 spec->autocfg.hp_pins[0] = 0x14;
9578 spec->autocfg.speaker_pins[0] = 0x1b;
9579 alc_automute_pin(codec);
Kailang Yange2757d52008-08-26 13:17:46 +02009580}
9581
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009582static struct hda_verb alc889A_mb31_verbs[] = {
9583 /* Init rear pin (used as headphone output) */
9584 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */
9585 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */
9586 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9587 /* Init line pin (used as output in 4ch and 6ch mode) */
9588 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Connect to CLFE */
9589 /* Init line 2 pin (used as headphone out by default) */
9590 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Use as input */
9591 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */
9592 { } /* end */
9593};
9594
9595/* Mute speakers according to the headphone jack state */
9596static void alc889A_mb31_automute(struct hda_codec *codec)
9597{
9598 unsigned int present;
9599
9600 /* Mute only in 2ch or 4ch mode */
9601 if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0)
9602 == 0x00) {
Wu Fengguang864f92b2009-11-18 12:38:02 +08009603 present = snd_hda_jack_detect(codec, 0x15);
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009604 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9605 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9606 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
9607 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9608 }
9609}
9610
9611static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
9612{
9613 if ((res >> 26) == ALC880_HP_EVENT)
9614 alc889A_mb31_automute(codec);
9615}
9616
Takashi Iwai49535502009-06-30 15:28:30 +02009617
Takashi Iwaicb53c622007-08-10 17:21:45 +02009618#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwai49535502009-06-30 15:28:30 +02009619#define alc882_loopbacks alc880_loopbacks
Takashi Iwaicb53c622007-08-10 17:21:45 +02009620#endif
9621
Sasha Alexandrdef319f2009-06-16 16:00:15 -04009622/* pcm configuration: identical with ALC880 */
Takashi Iwai49535502009-06-30 15:28:30 +02009623#define alc882_pcm_analog_playback alc880_pcm_analog_playback
9624#define alc882_pcm_analog_capture alc880_pcm_analog_capture
9625#define alc882_pcm_digital_playback alc880_pcm_digital_playback
9626#define alc882_pcm_digital_capture alc880_pcm_digital_capture
9627
9628static hda_nid_t alc883_slave_dig_outs[] = {
9629 ALC1200_DIGOUT_NID, 0,
9630};
9631
9632static hda_nid_t alc1200_slave_dig_outs[] = {
9633 ALC883_DIGOUT_NID, 0,
9634};
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009635
9636/*
9637 * configuration and preset
9638 */
Takashi Iwai49535502009-06-30 15:28:30 +02009639static const char *alc882_models[ALC882_MODEL_LAST] = {
9640 [ALC882_3ST_DIG] = "3stack-dig",
9641 [ALC882_6ST_DIG] = "6stack-dig",
9642 [ALC882_ARIMA] = "arima",
9643 [ALC882_W2JC] = "w2jc",
9644 [ALC882_TARGA] = "targa",
9645 [ALC882_ASUS_A7J] = "asus-a7j",
9646 [ALC882_ASUS_A7M] = "asus-a7m",
9647 [ALC885_MACPRO] = "macpro",
9648 [ALC885_MB5] = "mb5",
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009649 [ALC885_MACMINI3] = "macmini3",
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08009650 [ALC885_MBA21] = "mba21",
Takashi Iwai49535502009-06-30 15:28:30 +02009651 [ALC885_MBP3] = "mbp3",
9652 [ALC885_IMAC24] = "imac24",
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009653 [ALC885_IMAC91] = "imac91",
Takashi Iwai49535502009-06-30 15:28:30 +02009654 [ALC883_3ST_2ch_DIG] = "3stack-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009655 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
9656 [ALC883_3ST_6ch] = "3stack-6ch",
Takashi Iwai49535502009-06-30 15:28:30 +02009657 [ALC883_6ST_DIG] = "alc883-6stack-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009658 [ALC883_TARGA_DIG] = "targa-dig",
9659 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
David Heidelberger64a8be72009-06-08 16:15:18 +02009660 [ALC883_TARGA_8ch_DIG] = "targa-8ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009661 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02009662 [ALC883_ACER_ASPIRE] = "acer-aspire",
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009663 [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g",
Takashi Iwaib1a91462009-06-21 10:56:44 +02009664 [ALC888_ACER_ASPIRE_6530G] = "acer-aspire-6530g",
Hector Martin3b315d72009-06-02 10:54:19 +02009665 [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g",
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009666 [ALC888_ACER_ASPIRE_7730G] = "acer-aspire-7730g",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009667 [ALC883_MEDION] = "medion",
Kailang Yang272a5272007-05-14 11:00:38 +02009668 [ALC883_MEDION_MD2] = "medion-md2",
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009669 [ALC883_MEDION_WIM2160] = "medion-wim2160",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009670 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009671 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02009672 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
9673 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yange2757d52008-08-26 13:17:46 +02009674 [ALC888_LENOVO_SKY] = "lenovo-sky",
Kailang Yang189609a2007-08-20 11:31:23 +02009675 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009676 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009677 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009678 [ALC883_MITAC] = "mitac",
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309679 [ALC883_CLEVO_M540R] = "clevo-m540r",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009680 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +01009681 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009682 [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
Jiang zhe17bba1b2008-06-04 12:11:07 +02009683 [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009684 [ALC889A_INTEL] = "intel-alc889a",
9685 [ALC889_INTEL] = "intel-x58",
Wu Fengguang3ab90932008-11-17 09:51:09 +01009686 [ALC1200_ASUS_P5Q] = "asus-p5q",
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009687 [ALC889A_MB31] = "mb31",
Guido Günther3e1647c2009-06-05 00:47:26 +02009688 [ALC883_SONY_VAIO_TT] = "sony-vaio-tt",
Takashi Iwai49535502009-06-30 15:28:30 +02009689 [ALC882_AUTO] = "auto",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009690};
9691
Takashi Iwai49535502009-06-30 15:28:30 +02009692static struct snd_pci_quirk alc882_cfg_tbl[] = {
9693 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
9694
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009695 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
Takashi Iwai69e50282008-11-03 10:07:43 +01009696 SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
Takashi Iwai9b6682f2009-03-23 22:50:52 +01009697 SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009698 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
9699 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
Jaroslav Kysela0b18cb12008-07-28 17:07:07 +02009700 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009701 SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
9702 ALC888_ACER_ASPIRE_4930G),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01009703 SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
Takashi Iwai83dd7402009-11-24 08:57:53 +01009704 ALC888_ACER_ASPIRE_4930G),
Hector Martin3b315d72009-06-02 10:54:19 +02009705 SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
9706 ALC888_ACER_ASPIRE_8930G),
Takashi Iwaie46b0c82009-06-13 10:16:43 +02009707 SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
9708 ALC888_ACER_ASPIRE_8930G),
Takashi Iwai49535502009-06-30 15:28:30 +02009709 SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO),
9710 SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01009711 SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
Takashi Iwaidde65352009-06-25 08:25:35 +02009712 ALC888_ACER_ASPIRE_6530G),
Juan Jesus Garcia de Soriacc374c42009-02-23 08:11:59 +01009713 SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
Tony Vroond2fd4b02009-06-21 00:40:10 +01009714 ALC888_ACER_ASPIRE_6530G),
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009715 SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
9716 ALC888_ACER_ASPIRE_7730G),
Takashi Iwai22b530e2009-05-13 11:32:52 +02009717 /* default Acer -- disabled as it causes more problems.
9718 * model=auto should work fine now
9719 */
9720 /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */
Takashi Iwai49535502009-06-30 15:28:30 +02009721
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009722 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Takashi Iwai49535502009-06-30 15:28:30 +02009723
Tobin Davisfebe3372007-06-12 11:27:46 +02009724 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009725 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
9726 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +01009727 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Chris Bagwell06bf3e12009-01-01 10:32:08 +01009728 SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
Herton Ronaldo Krzesinski7ec30f02009-03-04 14:22:52 -03009729 SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
Takashi Iwai49535502009-06-30 15:28:30 +02009730
9731 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
9732 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
9733 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Kailang Yanga01c30c2008-10-15 11:14:58 +02009734 SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
Takashi Iwai49535502009-06-30 15:28:30 +02009735 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
9736 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
9737 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009738 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Mackenzie Morgan44a678d2009-02-10 17:13:43 +01009739 SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
Wu Fengguang3ab90932008-11-17 09:51:09 +01009740 SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
Kailang Yange2757d52008-08-26 13:17:46 +02009741 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
Takashi Iwai49535502009-06-30 15:28:30 +02009742
9743 SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
Travis Place97ec7102008-05-23 18:31:46 +02009744 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009745 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009746 SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009747 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
9748 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
Kailang Yange2757d52008-08-26 13:17:46 +02009749 SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009750 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Takashi Iwai49535502009-06-30 15:28:30 +02009751 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
9752
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009753 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
9754 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
9755 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009756 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
Takashi Iwai2fef62c2009-12-18 08:48:42 +01009757 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC882_AUTO),
Takashi Iwai49535502009-06-30 15:28:30 +02009758 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009759 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01009760 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009761 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
9762 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
9763 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
9764 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
9765 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
9766 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009767 SND_PCI_QUIRK(0x1462, 0x42cd, "MSI", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009768 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
9769 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
9770 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Anisse Astierb43f6e52010-03-10 19:17:46 +01009771 SND_PCI_QUIRK(0x1462, 0x4570, "MSI Wind Top AE2220", ALC883_TARGA_DIG),
David Heidelberger64a8be72009-06-08 16:15:18 +02009772 SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009773 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
9774 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02009775 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Takashi Iwaiee095432008-11-25 15:03:38 +01009776 SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +01009777 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01009778 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02009779 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Sasha Alexandrdf01b8a2009-06-16 14:46:17 -04009780 SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG),
Anisse Astierb43f6e52010-03-10 19:17:46 +01009781 SND_PCI_QUIRK(0x1462, 0x7437, "MSI NetOn AP1900", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009782 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009783 SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009784
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009785 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Joerg Schirottked1501ea2010-04-15 08:37:41 +02009786 SND_PCI_QUIRK(0x1558, 0x0571, "Clevo laptop M570U", ALC883_3ST_6ch_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009787 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
9788 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309789 SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R),
Takashi Iwaidea0a502009-02-09 17:14:52 +01009790 SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04009791 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwai49535502009-06-30 15:28:30 +02009792 /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009793 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009794 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
Takashi Iwaif67d8172009-02-04 23:30:19 +01009795 ALC883_FUJITSU_PI2515),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009796 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009797 ALC888_FUJITSU_XA3530),
Kailang Yang272a5272007-05-14 11:00:38 +02009798 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02009799 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009800 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
9801 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yange2757d52008-08-26 13:17:46 +02009802 SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
Kailang Yang272a5272007-05-14 11:00:38 +02009803 SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
Takashi Iwai959973b2008-11-05 11:30:56 +01009804 SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01009805 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02009806 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Takashi Iwai49535502009-06-30 15:28:30 +02009807
Jiang zhe17bba1b2008-06-04 12:11:07 +02009808 SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
9809 SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009810 SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009811 SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL),
9812 SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL),
9813 SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL),
Daniel T Chen572c0e32010-03-14 23:44:03 -04009814 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC882_6ST_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009815
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009816 {}
9817};
9818
Takashi Iwai49535502009-06-30 15:28:30 +02009819/* codec SSID table for Intel Mac */
9820static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
9821 SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3),
9822 SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3),
9823 SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3),
9824 SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO),
9825 SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24),
9826 SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24),
9827 SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3),
Daniel T Chen26fd74f2010-05-30 09:55:23 -04009828 SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31),
Justin P. Mattockab669962010-06-06 16:09:53 -07009829 SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_ASUS_A7M),
Justin P. Mattockf53dae22010-06-06 16:09:51 -07009830 SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC885_MBP3),
Justin P. Mattock6e129702010-06-06 16:09:49 -07009831 SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC885_MBA21),
Takashi Iwai49535502009-06-30 15:28:30 +02009832 SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
9833 SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
9834 SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009835 SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91),
Takashi Iwai49535502009-06-30 15:28:30 +02009836 SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5),
Luke Yelavich3bfea982010-06-22 11:04:19 +10009837 SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -05009838 /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2,
9839 * so apparently no perfect solution yet
Takashi Iwai49535502009-06-30 15:28:30 +02009840 */
9841 SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -05009842 SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5),
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009843 SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC885_MACMINI3),
Takashi Iwai49535502009-06-30 15:28:30 +02009844 {} /* terminator */
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08009845};
9846
Takashi Iwai49535502009-06-30 15:28:30 +02009847static struct alc_config_preset alc882_presets[] = {
9848 [ALC882_3ST_DIG] = {
9849 .mixers = { alc882_base_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009850 .init_verbs = { alc882_base_init_verbs,
9851 alc882_adc1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +02009852 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9853 .dac_nids = alc882_dac_nids,
9854 .dig_out_nid = ALC882_DIGOUT_NID,
9855 .dig_in_nid = ALC882_DIGIN_NID,
9856 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
9857 .channel_mode = alc882_ch_modes,
9858 .need_dac_fix = 1,
9859 .input_mux = &alc882_capture_source,
9860 },
9861 [ALC882_6ST_DIG] = {
9862 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009863 .init_verbs = { alc882_base_init_verbs,
9864 alc882_adc1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +02009865 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9866 .dac_nids = alc882_dac_nids,
9867 .dig_out_nid = ALC882_DIGOUT_NID,
9868 .dig_in_nid = ALC882_DIGIN_NID,
9869 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
9870 .channel_mode = alc882_sixstack_modes,
9871 .input_mux = &alc882_capture_source,
9872 },
9873 [ALC882_ARIMA] = {
9874 .mixers = { alc882_base_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 },
Takashi Iwai49535502009-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(alc882_sixstack_modes),
9880 .channel_mode = alc882_sixstack_modes,
9881 .input_mux = &alc882_capture_source,
9882 },
9883 [ALC882_W2JC] = {
9884 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009885 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9886 alc882_eapd_verbs, alc880_gpio1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +02009887 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9888 .dac_nids = alc882_dac_nids,
9889 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
9890 .channel_mode = alc880_threestack_modes,
9891 .need_dac_fix = 1,
9892 .input_mux = &alc882_capture_source,
9893 .dig_out_nid = ALC882_DIGOUT_NID,
9894 },
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08009895 [ALC885_MBA21] = {
9896 .mixers = { alc885_mba21_mixer },
9897 .init_verbs = { alc885_mba21_init_verbs, alc880_gpio1_init_verbs },
9898 .num_dacs = 2,
9899 .dac_nids = alc882_dac_nids,
9900 .channel_mode = alc885_mba21_ch_modes,
9901 .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
9902 .input_mux = &alc882_capture_source,
9903 .unsol_event = alc_automute_amp_unsol_event,
9904 .setup = alc885_mba21_setup,
9905 .init_hook = alc_automute_amp,
9906 },
Takashi Iwai49535502009-06-30 15:28:30 +02009907 [ALC885_MBP3] = {
9908 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
9909 .init_verbs = { alc885_mbp3_init_verbs,
9910 alc880_gpio1_init_verbs },
Takashi Iwaibe0ae922009-08-31 08:27:10 +02009911 .num_dacs = 2,
Takashi Iwai49535502009-06-30 15:28:30 +02009912 .dac_nids = alc882_dac_nids,
Takashi Iwaibe0ae922009-08-31 08:27:10 +02009913 .hp_nid = 0x04,
9914 .channel_mode = alc885_mbp_4ch_modes,
9915 .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes),
Takashi Iwai49535502009-06-30 15:28:30 +02009916 .input_mux = &alc882_capture_source,
9917 .dig_out_nid = ALC882_DIGOUT_NID,
9918 .dig_in_nid = ALC882_DIGIN_NID,
9919 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009920 .setup = alc885_mbp3_setup,
9921 .init_hook = alc_automute_amp,
Takashi Iwai49535502009-06-30 15:28:30 +02009922 },
9923 [ALC885_MB5] = {
9924 .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
9925 .init_verbs = { alc885_mb5_init_verbs,
9926 alc880_gpio1_init_verbs },
9927 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9928 .dac_nids = alc882_dac_nids,
9929 .channel_mode = alc885_mb5_6ch_modes,
9930 .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
9931 .input_mux = &mb5_capture_source,
9932 .dig_out_nid = ALC882_DIGOUT_NID,
9933 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +01009934 .unsol_event = alc_automute_amp_unsol_event,
9935 .setup = alc885_mb5_setup,
9936 .init_hook = alc_automute_amp,
Takashi Iwai49535502009-06-30 15:28:30 +02009937 },
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009938 [ALC885_MACMINI3] = {
9939 .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer },
9940 .init_verbs = { alc885_macmini3_init_verbs,
9941 alc880_gpio1_init_verbs },
9942 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9943 .dac_nids = alc882_dac_nids,
9944 .channel_mode = alc885_macmini3_6ch_modes,
9945 .num_channel_mode = ARRAY_SIZE(alc885_macmini3_6ch_modes),
9946 .input_mux = &macmini3_capture_source,
9947 .dig_out_nid = ALC882_DIGOUT_NID,
9948 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +01009949 .unsol_event = alc_automute_amp_unsol_event,
9950 .setup = alc885_macmini3_setup,
9951 .init_hook = alc_automute_amp,
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009952 },
Takashi Iwai49535502009-06-30 15:28:30 +02009953 [ALC885_MACPRO] = {
9954 .mixers = { alc882_macpro_mixer },
9955 .init_verbs = { alc882_macpro_init_verbs },
9956 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9957 .dac_nids = alc882_dac_nids,
9958 .dig_out_nid = ALC882_DIGOUT_NID,
9959 .dig_in_nid = ALC882_DIGIN_NID,
9960 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
9961 .channel_mode = alc882_ch_modes,
9962 .input_mux = &alc882_capture_source,
9963 .init_hook = alc885_macpro_init_hook,
9964 },
9965 [ALC885_IMAC24] = {
9966 .mixers = { alc885_imac24_mixer },
9967 .init_verbs = { alc885_imac24_init_verbs },
9968 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9969 .dac_nids = alc882_dac_nids,
9970 .dig_out_nid = ALC882_DIGOUT_NID,
9971 .dig_in_nid = ALC882_DIGIN_NID,
9972 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
9973 .channel_mode = alc882_ch_modes,
9974 .input_mux = &alc882_capture_source,
9975 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009976 .setup = alc885_imac24_setup,
Takashi Iwai49535502009-06-30 15:28:30 +02009977 .init_hook = alc885_imac24_init_hook,
9978 },
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009979 [ALC885_IMAC91] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07009980 .mixers = {alc885_imac91_mixer},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009981 .init_verbs = { alc885_imac91_init_verbs,
9982 alc880_gpio1_init_verbs },
9983 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9984 .dac_nids = alc882_dac_nids,
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07009985 .channel_mode = alc885_mba21_ch_modes,
9986 .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
9987 .input_mux = &alc889A_imac91_capture_source,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009988 .dig_out_nid = ALC882_DIGOUT_NID,
9989 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +01009990 .unsol_event = alc_automute_amp_unsol_event,
9991 .setup = alc885_imac91_setup,
9992 .init_hook = alc_automute_amp,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009993 },
Takashi Iwai49535502009-06-30 15:28:30 +02009994 [ALC882_TARGA] = {
9995 .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009996 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
Takashi Iwai31909b82009-07-10 12:33:48 +02009997 alc880_gpio3_init_verbs, alc882_targa_verbs},
Takashi Iwai49535502009-06-30 15:28:30 +02009998 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9999 .dac_nids = alc882_dac_nids,
10000 .dig_out_nid = ALC882_DIGOUT_NID,
10001 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
10002 .adc_nids = alc882_adc_nids,
10003 .capsrc_nids = alc882_capsrc_nids,
10004 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
10005 .channel_mode = alc882_3ST_6ch_modes,
10006 .need_dac_fix = 1,
10007 .input_mux = &alc882_capture_source,
10008 .unsol_event = alc882_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010009 .setup = alc882_targa_setup,
10010 .init_hook = alc882_targa_automute,
Takashi Iwai49535502009-06-30 15:28:30 +020010011 },
10012 [ALC882_ASUS_A7J] = {
10013 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010014 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10015 alc882_asus_a7j_verbs},
Takashi Iwai49535502009-06-30 15:28:30 +020010016 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10017 .dac_nids = alc882_dac_nids,
10018 .dig_out_nid = ALC882_DIGOUT_NID,
10019 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
10020 .adc_nids = alc882_adc_nids,
10021 .capsrc_nids = alc882_capsrc_nids,
10022 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
10023 .channel_mode = alc882_3ST_6ch_modes,
10024 .need_dac_fix = 1,
10025 .input_mux = &alc882_capture_source,
10026 },
10027 [ALC882_ASUS_A7M] = {
10028 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010029 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10030 alc882_eapd_verbs, alc880_gpio1_init_verbs,
Takashi Iwai49535502009-06-30 15:28:30 +020010031 alc882_asus_a7m_verbs },
10032 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10033 .dac_nids = alc882_dac_nids,
10034 .dig_out_nid = ALC882_DIGOUT_NID,
10035 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
10036 .channel_mode = alc880_threestack_modes,
10037 .need_dac_fix = 1,
10038 .input_mux = &alc882_capture_source,
10039 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010040 [ALC883_3ST_2ch_DIG] = {
10041 .mixers = { alc883_3ST_2ch_mixer },
10042 .init_verbs = { alc883_init_verbs },
10043 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10044 .dac_nids = alc883_dac_nids,
10045 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010046 .dig_in_nid = ALC883_DIGIN_NID,
10047 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10048 .channel_mode = alc883_3ST_2ch_modes,
10049 .input_mux = &alc883_capture_source,
10050 },
10051 [ALC883_3ST_6ch_DIG] = {
10052 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10053 .init_verbs = { alc883_init_verbs },
10054 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10055 .dac_nids = alc883_dac_nids,
10056 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010057 .dig_in_nid = ALC883_DIGIN_NID,
10058 .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 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010063 [ALC883_3ST_6ch] = {
10064 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10065 .init_verbs = { alc883_init_verbs },
10066 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10067 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010068 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10069 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020010070 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010071 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010072 },
Jiang zhe17bba1b2008-06-04 12:11:07 +020010073 [ALC883_3ST_6ch_INTEL] = {
10074 .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
10075 .init_verbs = { alc883_init_verbs },
10076 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10077 .dac_nids = alc883_dac_nids,
10078 .dig_out_nid = ALC883_DIGOUT_NID,
10079 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangf3cd3f52009-04-02 19:44:18 +080010080 .slave_dig_outs = alc883_slave_dig_outs,
Jiang zhe17bba1b2008-06-04 12:11:07 +020010081 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
10082 .channel_mode = alc883_3ST_6ch_intel_modes,
10083 .need_dac_fix = 1,
10084 .input_mux = &alc883_3stack_6ch_intel,
10085 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010086 [ALC889A_INTEL] = {
10087 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020010088 .init_verbs = { alc885_init_verbs, alc885_init_input_verbs,
10089 alc_hp15_unsol_verbs },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010090 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10091 .dac_nids = alc883_dac_nids,
10092 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10093 .adc_nids = alc889_adc_nids,
10094 .dig_out_nid = ALC883_DIGOUT_NID,
10095 .dig_in_nid = ALC883_DIGIN_NID,
10096 .slave_dig_outs = alc883_slave_dig_outs,
10097 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
10098 .channel_mode = alc889_8ch_intel_modes,
10099 .capsrc_nids = alc889_capsrc_nids,
10100 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010101 .setup = alc889_automute_setup,
10102 .init_hook = alc_automute_amp,
Wu Fengguang6732bd02009-07-30 09:19:14 +020010103 .unsol_event = alc_automute_amp_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010104 .need_dac_fix = 1,
10105 },
10106 [ALC889_INTEL] = {
10107 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
10108 .init_verbs = { alc885_init_verbs, alc889_init_input_verbs,
Wu Fengguang6732bd02009-07-30 09:19:14 +020010109 alc889_eapd_verbs, alc_hp15_unsol_verbs},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010110 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10111 .dac_nids = alc883_dac_nids,
10112 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10113 .adc_nids = alc889_adc_nids,
10114 .dig_out_nid = ALC883_DIGOUT_NID,
10115 .dig_in_nid = ALC883_DIGIN_NID,
10116 .slave_dig_outs = alc883_slave_dig_outs,
10117 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
10118 .channel_mode = alc889_8ch_intel_modes,
10119 .capsrc_nids = alc889_capsrc_nids,
10120 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010121 .setup = alc889_automute_setup,
Wu Fengguang6732bd02009-07-30 09:19:14 +020010122 .init_hook = alc889_intel_init_hook,
10123 .unsol_event = alc_automute_amp_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010124 .need_dac_fix = 1,
10125 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010126 [ALC883_6ST_DIG] = {
10127 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
10128 .init_verbs = { alc883_init_verbs },
10129 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10130 .dac_nids = alc883_dac_nids,
10131 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010132 .dig_in_nid = ALC883_DIGIN_NID,
10133 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10134 .channel_mode = alc883_sixstack_modes,
10135 .input_mux = &alc883_capture_source,
10136 },
Kailang Yangccc656c2006-10-17 12:32:26 +020010137 [ALC883_TARGA_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010138 .mixers = { alc883_targa_mixer, alc883_chmode_mixer },
David Heidelberger005b1072009-07-09 18:45:46 +020010139 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
10140 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020010141 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10142 .dac_nids = alc883_dac_nids,
10143 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +020010144 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10145 .channel_mode = alc883_3ST_6ch_modes,
10146 .need_dac_fix = 1,
10147 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010148 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010149 .setup = alc882_targa_setup,
10150 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010151 },
10152 [ALC883_TARGA_2ch_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010153 .mixers = { alc883_targa_2ch_mixer},
David Heidelberger005b1072009-07-09 18:45:46 +020010154 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
10155 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020010156 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10157 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010158 .adc_nids = alc883_adc_nids_alt,
10159 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010160 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangccc656c2006-10-17 12:32:26 +020010161 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +020010162 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10163 .channel_mode = alc883_3ST_2ch_modes,
10164 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010165 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010166 .setup = alc882_targa_setup,
10167 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010168 },
David Heidelberger64a8be72009-06-08 16:15:18 +020010169 [ALC883_TARGA_8ch_DIG] = {
Takashi Iwaib99dba32009-09-17 18:23:00 +020010170 .mixers = { alc883_targa_mixer, alc883_targa_8ch_mixer,
10171 alc883_chmode_mixer },
David Heidelberger64a8be72009-06-08 16:15:18 +020010172 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010173 alc883_targa_verbs },
David Heidelberger64a8be72009-06-08 16:15:18 +020010174 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10175 .dac_nids = alc883_dac_nids,
10176 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10177 .adc_nids = alc883_adc_nids_rev,
10178 .capsrc_nids = alc883_capsrc_nids_rev,
10179 .dig_out_nid = ALC883_DIGOUT_NID,
10180 .dig_in_nid = ALC883_DIGIN_NID,
10181 .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes),
10182 .channel_mode = alc883_4ST_8ch_modes,
10183 .need_dac_fix = 1,
10184 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010185 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010186 .setup = alc882_targa_setup,
10187 .init_hook = alc882_targa_automute,
David Heidelberger64a8be72009-06-08 16:15:18 +020010188 },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +020010189 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010190 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +020010191 /* On TravelMate laptops, GPIO 0 enables the internal speaker
10192 * and the headphone jack. Turn this on and rely on the
10193 * standard mute methods whenever the user wants to turn
10194 * these outputs off.
10195 */
10196 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
10197 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10198 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +020010199 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10200 .channel_mode = alc883_3ST_2ch_modes,
10201 .input_mux = &alc883_capture_source,
10202 },
Tobin Davis2880a862007-08-07 11:50:26 +020010203 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010204 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +020010205 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +020010206 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10207 .dac_nids = alc883_dac_nids,
10208 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +020010209 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10210 .channel_mode = alc883_3ST_2ch_modes,
10211 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010212 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010213 .setup = alc883_acer_aspire_setup,
10214 .init_hook = alc_automute_amp,
Kailang Yangd1a991a2007-08-15 16:21:59 +020010215 },
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010216 [ALC888_ACER_ASPIRE_4930G] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010217 .mixers = { alc888_base_mixer,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010218 alc883_chmode_mixer },
10219 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10220 alc888_acer_aspire_4930g_verbs },
10221 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10222 .dac_nids = alc883_dac_nids,
10223 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10224 .adc_nids = alc883_adc_nids_rev,
10225 .capsrc_nids = alc883_capsrc_nids_rev,
10226 .dig_out_nid = ALC883_DIGOUT_NID,
10227 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10228 .channel_mode = alc883_3ST_6ch_modes,
10229 .need_dac_fix = 1,
Łukasz Wojniłowicz973b8cb2010-01-24 14:12:37 +010010230 .const_channel_count = 6,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010231 .num_mux_defs =
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010232 ARRAY_SIZE(alc888_2_capture_sources),
10233 .input_mux = alc888_2_capture_sources,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010234 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010235 .setup = alc888_acer_aspire_4930g_setup,
10236 .init_hook = alc_automute_amp,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010237 },
Tony Vroond2fd4b02009-06-21 00:40:10 +010010238 [ALC888_ACER_ASPIRE_6530G] = {
10239 .mixers = { alc888_acer_aspire_6530_mixer },
10240 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10241 alc888_acer_aspire_6530g_verbs },
10242 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10243 .dac_nids = alc883_dac_nids,
10244 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10245 .adc_nids = alc883_adc_nids_rev,
10246 .capsrc_nids = alc883_capsrc_nids_rev,
10247 .dig_out_nid = ALC883_DIGOUT_NID,
10248 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10249 .channel_mode = alc883_3ST_2ch_modes,
10250 .num_mux_defs =
10251 ARRAY_SIZE(alc888_2_capture_sources),
10252 .input_mux = alc888_acer_aspire_6530_sources,
10253 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010254 .setup = alc888_acer_aspire_6530g_setup,
10255 .init_hook = alc_automute_amp,
Tony Vroond2fd4b02009-06-21 00:40:10 +010010256 },
Hector Martin3b315d72009-06-02 10:54:19 +020010257 [ALC888_ACER_ASPIRE_8930G] = {
Hector Martin556eea92009-12-20 22:51:23 +010010258 .mixers = { alc889_acer_aspire_8930g_mixer,
Hector Martin3b315d72009-06-02 10:54:19 +020010259 alc883_chmode_mixer },
10260 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
Hector Martin0f86a222009-12-20 22:51:18 +010010261 alc889_acer_aspire_8930g_verbs,
10262 alc889_eapd_verbs},
Hector Martin3b315d72009-06-02 10:54:19 +020010263 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10264 .dac_nids = alc883_dac_nids,
Hector Martin018df412009-06-04 00:13:40 +020010265 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10266 .adc_nids = alc889_adc_nids,
10267 .capsrc_nids = alc889_capsrc_nids,
Hector Martin3b315d72009-06-02 10:54:19 +020010268 .dig_out_nid = ALC883_DIGOUT_NID,
10269 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10270 .channel_mode = alc883_3ST_6ch_modes,
10271 .need_dac_fix = 1,
10272 .const_channel_count = 6,
10273 .num_mux_defs =
Hector Martin018df412009-06-04 00:13:40 +020010274 ARRAY_SIZE(alc889_capture_sources),
10275 .input_mux = alc889_capture_sources,
Hector Martin3b315d72009-06-02 10:54:19 +020010276 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010277 .setup = alc889_acer_aspire_8930g_setup,
10278 .init_hook = alc_automute_amp,
Hector Martinf5de24b2009-12-20 22:51:31 +010010279#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050010280 .power_hook = alc_power_eapd,
Hector Martinf5de24b2009-12-20 22:51:31 +010010281#endif
Hector Martin3b315d72009-06-02 10:54:19 +020010282 },
Denis Kuplyakovfc86f952009-08-25 18:15:59 +020010283 [ALC888_ACER_ASPIRE_7730G] = {
10284 .mixers = { alc883_3ST_6ch_mixer,
10285 alc883_chmode_mixer },
10286 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10287 alc888_acer_aspire_7730G_verbs },
10288 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10289 .dac_nids = alc883_dac_nids,
10290 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10291 .adc_nids = alc883_adc_nids_rev,
10292 .capsrc_nids = alc883_capsrc_nids_rev,
10293 .dig_out_nid = ALC883_DIGOUT_NID,
10294 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10295 .channel_mode = alc883_3ST_6ch_modes,
10296 .need_dac_fix = 1,
10297 .const_channel_count = 6,
10298 .input_mux = &alc883_capture_source,
10299 .unsol_event = alc_automute_amp_unsol_event,
10300 .setup = alc888_acer_aspire_6530g_setup,
10301 .init_hook = alc_automute_amp,
10302 },
Tobin Davisc07584c2006-10-13 12:32:16 +020010303 [ALC883_MEDION] = {
10304 .mixers = { alc883_fivestack_mixer,
10305 alc883_chmode_mixer },
10306 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010307 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +020010308 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10309 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010310 .adc_nids = alc883_adc_nids_alt,
10311 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010312 .capsrc_nids = alc883_capsrc_nids,
Tobin Davisc07584c2006-10-13 12:32:16 +020010313 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10314 .channel_mode = alc883_sixstack_modes,
10315 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010316 },
Kailang Yang272a5272007-05-14 11:00:38 +020010317 [ALC883_MEDION_MD2] = {
10318 .mixers = { alc883_medion_md2_mixer},
10319 .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
10320 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10321 .dac_nids = alc883_dac_nids,
10322 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +020010323 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10324 .channel_mode = alc883_3ST_2ch_modes,
10325 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010326 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010327 .setup = alc883_medion_md2_setup,
10328 .init_hook = alc_automute_amp,
Kailang Yangea1fb292008-08-26 12:58:38 +020010329 },
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +020010330 [ALC883_MEDION_WIM2160] = {
10331 .mixers = { alc883_medion_wim2160_mixer },
10332 .init_verbs = { alc883_init_verbs, alc883_medion_wim2160_verbs },
10333 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10334 .dac_nids = alc883_dac_nids,
10335 .dig_out_nid = ALC883_DIGOUT_NID,
10336 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
10337 .adc_nids = alc883_adc_nids,
10338 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10339 .channel_mode = alc883_3ST_2ch_modes,
10340 .input_mux = &alc883_capture_source,
10341 .unsol_event = alc_automute_amp_unsol_event,
10342 .setup = alc883_medion_wim2160_setup,
10343 .init_hook = alc_automute_amp,
10344 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010345 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010346 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010347 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
10348 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10349 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010350 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10351 .channel_mode = alc883_3ST_2ch_modes,
10352 .input_mux = &alc883_capture_source,
10353 },
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -043010354 [ALC883_CLEVO_M540R] = {
10355 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10356 .init_verbs = { alc883_init_verbs, alc883_clevo_m540r_verbs },
10357 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10358 .dac_nids = alc883_dac_nids,
10359 .dig_out_nid = ALC883_DIGOUT_NID,
10360 .dig_in_nid = ALC883_DIGIN_NID,
10361 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_clevo_modes),
10362 .channel_mode = alc883_3ST_6ch_clevo_modes,
10363 .need_dac_fix = 1,
10364 .input_mux = &alc883_capture_source,
10365 /* This machine has the hardware HP auto-muting, thus
10366 * we need no software mute via unsol event
10367 */
10368 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010369 [ALC883_CLEVO_M720] = {
10370 .mixers = { alc883_clevo_m720_mixer },
10371 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +010010372 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10373 .dac_nids = alc883_dac_nids,
10374 .dig_out_nid = ALC883_DIGOUT_NID,
10375 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10376 .channel_mode = alc883_3ST_2ch_modes,
10377 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010378 .unsol_event = alc883_clevo_m720_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010379 .setup = alc883_clevo_m720_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010380 .init_hook = alc883_clevo_m720_init_hook,
Jiang zhe368c7a92008-03-04 11:20:33 +010010381 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010382 [ALC883_LENOVO_101E_2ch] = {
10383 .mixers = { alc883_lenovo_101e_2ch_mixer},
10384 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
10385 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10386 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010387 .adc_nids = alc883_adc_nids_alt,
10388 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010389 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010390 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10391 .channel_mode = alc883_3ST_2ch_modes,
10392 .input_mux = &alc883_lenovo_101e_capture_source,
10393 .unsol_event = alc883_lenovo_101e_unsol_event,
10394 .init_hook = alc883_lenovo_101e_all_automute,
10395 },
Kailang Yang272a5272007-05-14 11:00:38 +020010396 [ALC883_LENOVO_NB0763] = {
10397 .mixers = { alc883_lenovo_nb0763_mixer },
10398 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
10399 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10400 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020010401 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10402 .channel_mode = alc883_3ST_2ch_modes,
10403 .need_dac_fix = 1,
10404 .input_mux = &alc883_lenovo_nb0763_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010405 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010406 .setup = alc883_medion_md2_setup,
10407 .init_hook = alc_automute_amp,
Kailang Yang272a5272007-05-14 11:00:38 +020010408 },
10409 [ALC888_LENOVO_MS7195_DIG] = {
10410 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10411 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
10412 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10413 .dac_nids = alc883_dac_nids,
10414 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +020010415 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10416 .channel_mode = alc883_3ST_6ch_modes,
10417 .need_dac_fix = 1,
10418 .input_mux = &alc883_capture_source,
10419 .unsol_event = alc883_lenovo_ms7195_unsol_event,
10420 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +020010421 },
10422 [ALC883_HAIER_W66] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010423 .mixers = { alc883_targa_2ch_mixer},
Kailang Yang189609a2007-08-20 11:31:23 +020010424 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
10425 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10426 .dac_nids = alc883_dac_nids,
10427 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +020010428 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10429 .channel_mode = alc883_3ST_2ch_modes,
10430 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010431 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010432 .setup = alc883_haier_w66_setup,
10433 .init_hook = alc_automute_amp,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +010010434 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010435 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +010010436 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010437 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010438 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10439 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010440 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
10441 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010442 .need_dac_fix = 1,
10443 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010444 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010445 .setup = alc888_3st_hp_setup,
10446 .init_hook = alc_automute_amp,
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010447 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010448 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +010010449 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010450 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
10451 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10452 .dac_nids = alc883_dac_nids,
10453 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010454 .dig_in_nid = ALC883_DIGIN_NID,
10455 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10456 .channel_mode = alc883_sixstack_modes,
10457 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010458 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010459 .setup = alc888_6st_dell_setup,
10460 .init_hook = alc_automute_amp,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010461 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010462 [ALC883_MITAC] = {
10463 .mixers = { alc883_mitac_mixer },
10464 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
10465 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10466 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010467 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10468 .channel_mode = alc883_3ST_2ch_modes,
10469 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010470 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010471 .setup = alc883_mitac_setup,
10472 .init_hook = alc_automute_amp,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010473 },
Jiang zhefb97dc62008-03-06 11:07:11 +010010474 [ALC883_FUJITSU_PI2515] = {
10475 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
10476 .init_verbs = { alc883_init_verbs,
10477 alc883_2ch_fujitsu_pi2515_verbs},
10478 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10479 .dac_nids = alc883_dac_nids,
10480 .dig_out_nid = ALC883_DIGOUT_NID,
10481 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10482 .channel_mode = alc883_3ST_2ch_modes,
10483 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010484 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010485 .setup = alc883_2ch_fujitsu_pi2515_setup,
10486 .init_hook = alc_automute_amp,
Jiang zhefb97dc62008-03-06 11:07:11 +010010487 },
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010488 [ALC888_FUJITSU_XA3530] = {
10489 .mixers = { alc888_base_mixer, alc883_chmode_mixer },
10490 .init_verbs = { alc883_init_verbs,
10491 alc888_fujitsu_xa3530_verbs },
10492 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10493 .dac_nids = alc883_dac_nids,
10494 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10495 .adc_nids = alc883_adc_nids_rev,
10496 .capsrc_nids = alc883_capsrc_nids_rev,
10497 .dig_out_nid = ALC883_DIGOUT_NID,
10498 .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes),
10499 .channel_mode = alc888_4ST_8ch_intel_modes,
10500 .num_mux_defs =
10501 ARRAY_SIZE(alc888_2_capture_sources),
10502 .input_mux = alc888_2_capture_sources,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010503 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010504 .setup = alc888_fujitsu_xa3530_setup,
10505 .init_hook = alc_automute_amp,
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010506 },
Kailang Yange2757d52008-08-26 13:17:46 +020010507 [ALC888_LENOVO_SKY] = {
10508 .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
10509 .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
10510 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10511 .dac_nids = alc883_dac_nids,
10512 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yange2757d52008-08-26 13:17:46 +020010513 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10514 .channel_mode = alc883_sixstack_modes,
10515 .need_dac_fix = 1,
10516 .input_mux = &alc883_lenovo_sky_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010517 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010518 .setup = alc888_lenovo_sky_setup,
10519 .init_hook = alc_automute_amp,
Kailang Yange2757d52008-08-26 13:17:46 +020010520 },
10521 [ALC888_ASUS_M90V] = {
10522 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10523 .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
10524 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10525 .dac_nids = alc883_dac_nids,
10526 .dig_out_nid = ALC883_DIGOUT_NID,
10527 .dig_in_nid = ALC883_DIGIN_NID,
10528 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10529 .channel_mode = alc883_3ST_6ch_modes,
10530 .need_dac_fix = 1,
10531 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010532 .unsol_event = alc_sku_unsol_event,
10533 .setup = alc883_mode2_setup,
10534 .init_hook = alc_inithook,
Kailang Yange2757d52008-08-26 13:17:46 +020010535 },
10536 [ALC888_ASUS_EEE1601] = {
10537 .mixers = { alc883_asus_eee1601_mixer },
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010538 .cap_mixer = alc883_asus_eee1601_cap_mixer,
Kailang Yange2757d52008-08-26 13:17:46 +020010539 .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
10540 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10541 .dac_nids = alc883_dac_nids,
10542 .dig_out_nid = ALC883_DIGOUT_NID,
10543 .dig_in_nid = ALC883_DIGIN_NID,
10544 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10545 .channel_mode = alc883_3ST_2ch_modes,
10546 .need_dac_fix = 1,
10547 .input_mux = &alc883_asus_eee1601_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010548 .unsol_event = alc_sku_unsol_event,
Kailang Yange2757d52008-08-26 13:17:46 +020010549 .init_hook = alc883_eee1601_inithook,
10550 },
Wu Fengguang3ab90932008-11-17 09:51:09 +010010551 [ALC1200_ASUS_P5Q] = {
10552 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
10553 .init_verbs = { alc883_init_verbs },
10554 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10555 .dac_nids = alc883_dac_nids,
10556 .dig_out_nid = ALC1200_DIGOUT_NID,
10557 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangb25c9da2009-02-06 15:02:27 +080010558 .slave_dig_outs = alc1200_slave_dig_outs,
Wu Fengguang3ab90932008-11-17 09:51:09 +010010559 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10560 .channel_mode = alc883_sixstack_modes,
10561 .input_mux = &alc883_capture_source,
10562 },
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010563 [ALC889A_MB31] = {
10564 .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer},
10565 .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs,
10566 alc880_gpio1_init_verbs },
10567 .adc_nids = alc883_adc_nids,
10568 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010569 .capsrc_nids = alc883_capsrc_nids,
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010570 .dac_nids = alc883_dac_nids,
10571 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10572 .channel_mode = alc889A_mb31_6ch_modes,
10573 .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes),
10574 .input_mux = &alc889A_mb31_capture_source,
10575 .dig_out_nid = ALC883_DIGOUT_NID,
10576 .unsol_event = alc889A_mb31_unsol_event,
10577 .init_hook = alc889A_mb31_automute,
10578 },
Guido Günther3e1647c2009-06-05 00:47:26 +020010579 [ALC883_SONY_VAIO_TT] = {
10580 .mixers = { alc883_vaiott_mixer },
10581 .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs },
10582 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10583 .dac_nids = alc883_dac_nids,
10584 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10585 .channel_mode = alc883_3ST_2ch_modes,
10586 .input_mux = &alc883_capture_source,
10587 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010588 .setup = alc883_vaiott_setup,
10589 .init_hook = alc_automute_amp,
Guido Günther3e1647c2009-06-05 00:47:26 +020010590 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010591};
10592
10593
10594/*
Takashi Iwai49535502009-06-30 15:28:30 +020010595 * Pin config fixes
10596 */
10597enum {
Takashi Iwai954a29c2010-07-30 10:55:44 +020010598 PINFIX_ABIT_AW9D_MAX,
10599 PINFIX_PB_M5210,
Takashi Iwai49535502009-06-30 15:28:30 +020010600};
10601
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010602static const struct alc_fixup alc882_fixups[] = {
10603 [PINFIX_ABIT_AW9D_MAX] = {
Takashi Iwai73413b12010-08-30 09:39:57 +020010604 .pins = (const struct alc_pincfg[]) {
10605 { 0x15, 0x01080104 }, /* side */
10606 { 0x16, 0x01011012 }, /* rear */
10607 { 0x17, 0x01016011 }, /* clfe */
10608 { }
10609 }
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010610 },
Takashi Iwai954a29c2010-07-30 10:55:44 +020010611 [PINFIX_PB_M5210] = {
Takashi Iwai73413b12010-08-30 09:39:57 +020010612 .verbs = (const struct hda_verb[]) {
10613 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
10614 {}
10615 }
Takashi Iwai954a29c2010-07-30 10:55:44 +020010616 },
Takashi Iwai49535502009-06-30 15:28:30 +020010617};
10618
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010619static struct snd_pci_quirk alc882_fixup_tbl[] = {
Takashi Iwai954a29c2010-07-30 10:55:44 +020010620 SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
Takashi Iwai49535502009-06-30 15:28:30 +020010621 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
10622 {}
10623};
10624
10625/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010626 * BIOS auto configuration
10627 */
Takashi Iwai05f5f472009-08-25 13:10:18 +020010628static int alc882_auto_create_input_ctls(struct hda_codec *codec,
10629 const struct auto_pin_cfg *cfg)
10630{
10631 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x23, 0x22);
10632}
10633
Takashi Iwai49535502009-06-30 15:28:30 +020010634static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010635 hda_nid_t nid, int pin_type,
Takashi Iwai489008c2010-04-07 09:06:00 +020010636 hda_nid_t dac)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010637{
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010638 int idx;
10639
Takashi Iwai489008c2010-04-07 09:06:00 +020010640 /* set as output */
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010641 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010642
Takashi Iwai489008c2010-04-07 09:06:00 +020010643 if (dac == 0x25)
10644 idx = 4;
10645 else if (dac >= 0x02 && dac <= 0x05)
10646 idx = dac - 2;
10647 else
10648 return;
10649 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010650}
10651
Takashi Iwai49535502009-06-30 15:28:30 +020010652static void alc882_auto_init_multi_out(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010653{
10654 struct alc_spec *spec = codec->spec;
10655 int i;
10656
10657 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010658 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020010659 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010660 if (nid)
Takashi Iwai49535502009-06-30 15:28:30 +020010661 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai489008c2010-04-07 09:06:00 +020010662 spec->multiout.dac_nids[i]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010663 }
10664}
10665
Takashi Iwai49535502009-06-30 15:28:30 +020010666static void alc882_auto_init_hp_out(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010667{
10668 struct alc_spec *spec = codec->spec;
Takashi Iwai489008c2010-04-07 09:06:00 +020010669 hda_nid_t pin, dac;
Takashi Iwai5855fb82010-09-16 18:24:02 +020010670 int i;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010671
Takashi Iwai5855fb82010-09-16 18:24:02 +020010672 for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
10673 pin = spec->autocfg.hp_pins[i];
10674 if (!pin)
10675 break;
Takashi Iwai489008c2010-04-07 09:06:00 +020010676 dac = spec->multiout.hp_nid;
10677 if (!dac)
10678 dac = spec->multiout.dac_nids[0]; /* to front */
10679 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
10680 }
Takashi Iwai5855fb82010-09-16 18:24:02 +020010681 for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
10682 pin = spec->autocfg.speaker_pins[i];
10683 if (!pin)
10684 break;
Takashi Iwai489008c2010-04-07 09:06:00 +020010685 dac = spec->multiout.extra_out_nid[0];
10686 if (!dac)
10687 dac = spec->multiout.dac_nids[0]; /* to front */
10688 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
10689 }
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010690}
10691
Takashi Iwai49535502009-06-30 15:28:30 +020010692static void alc882_auto_init_analog_input(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010693{
10694 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010695 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010696 int i;
10697
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010698 for (i = 0; i < cfg->num_inputs; i++) {
10699 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai30ea0982010-09-16 18:47:56 +020010700 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwai49535502009-06-30 15:28:30 +020010701 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
10702 snd_hda_codec_write(codec, nid, 0,
10703 AC_VERB_SET_AMP_GAIN_MUTE,
10704 AMP_OUT_MUTE);
10705 }
10706}
10707
10708static void alc882_auto_init_input_src(struct hda_codec *codec)
10709{
10710 struct alc_spec *spec = codec->spec;
10711 int c;
10712
10713 for (c = 0; c < spec->num_adc_nids; c++) {
10714 hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
10715 hda_nid_t nid = spec->capsrc_nids[c];
10716 unsigned int mux_idx;
10717 const struct hda_input_mux *imux;
10718 int conns, mute, idx, item;
10719
10720 conns = snd_hda_get_connections(codec, nid, conn_list,
10721 ARRAY_SIZE(conn_list));
10722 if (conns < 0)
10723 continue;
10724 mux_idx = c >= spec->num_mux_defs ? 0 : c;
10725 imux = &spec->input_mux[mux_idx];
Takashi Iwai53111142010-03-08 12:13:07 +010010726 if (!imux->num_items && mux_idx > 0)
10727 imux = &spec->input_mux[0];
Takashi Iwai49535502009-06-30 15:28:30 +020010728 for (idx = 0; idx < conns; idx++) {
10729 /* if the current connection is the selected one,
10730 * unmute it as default - otherwise mute it
10731 */
10732 mute = AMP_IN_MUTE(idx);
10733 for (item = 0; item < imux->num_items; item++) {
10734 if (imux->items[item].index == idx) {
10735 if (spec->cur_mux[c] == item)
10736 mute = AMP_IN_UNMUTE(idx);
10737 break;
10738 }
10739 }
10740 /* check if we have a selector or mixer
10741 * we could check for the widget type instead, but
10742 * just check for Amp-In presence (in case of mixer
10743 * without amp-in there is something wrong, this
10744 * function shouldn't be used or capsrc nid is wrong)
10745 */
10746 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010747 snd_hda_codec_write(codec, nid, 0,
10748 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwai49535502009-06-30 15:28:30 +020010749 mute);
10750 else if (mute != AMP_IN_MUTE(idx))
10751 snd_hda_codec_write(codec, nid, 0,
10752 AC_VERB_SET_CONNECT_SEL,
10753 idx);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010754 }
10755 }
10756}
10757
Takashi Iwai49535502009-06-30 15:28:30 +020010758/* add mic boosts if needed */
10759static int alc_auto_add_mic_boost(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010760{
10761 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010762 struct auto_pin_cfg *cfg = &spec->autocfg;
10763 int i, err;
Takashi Iwai49535502009-06-30 15:28:30 +020010764 hda_nid_t nid;
10765
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010766 for (i = 0; i < cfg->num_inputs; i++) {
Takashi Iwai86e29592010-09-09 14:50:17 +020010767 if (cfg->inputs[i].type > AUTO_PIN_MIC)
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010768 break;
10769 nid = cfg->inputs[i].pin;
10770 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
Takashi Iwai10a20af2010-09-09 16:28:02 +020010771 char label[32];
10772 snprintf(label, sizeof(label), "%s Boost",
10773 hda_get_autocfg_input_label(codec, cfg, i));
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010774 err = add_control(spec, ALC_CTL_WIDGET_VOL, label, 0,
Takashi Iwai49535502009-06-30 15:28:30 +020010775 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010776 if (err < 0)
10777 return err;
10778 }
Takashi Iwai49535502009-06-30 15:28:30 +020010779 }
10780 return 0;
10781}
10782
10783/* almost identical with ALC880 parser... */
10784static int alc882_parse_auto_config(struct hda_codec *codec)
10785{
10786 struct alc_spec *spec = codec->spec;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010787 static hda_nid_t alc882_ignore[] = { 0x1d, 0 };
Takashi Iwai757899a2010-07-30 10:48:14 +020010788 int err;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010789
Takashi Iwai05f5f472009-08-25 13:10:18 +020010790 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10791 alc882_ignore);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010792 if (err < 0)
10793 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010794 if (!spec->autocfg.line_outs)
10795 return 0; /* can't find valid BIOS pin config */
10796
10797 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
10798 if (err < 0)
10799 return err;
10800 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
10801 if (err < 0)
10802 return err;
Takashi Iwai489008c2010-04-07 09:06:00 +020010803 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
10804 "Headphone");
10805 if (err < 0)
10806 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010807 err = alc880_auto_create_extra_out(spec,
10808 spec->autocfg.speaker_pins[0],
10809 "Speaker");
10810 if (err < 0)
10811 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010812 err = alc882_auto_create_input_ctls(codec, &spec->autocfg);
10813 if (err < 0)
10814 return err;
10815
10816 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10817
Takashi Iwai757899a2010-07-30 10:48:14 +020010818 alc_auto_parse_digital(codec);
Takashi Iwai05f5f472009-08-25 13:10:18 +020010819
10820 if (spec->kctls.list)
10821 add_mixer(spec, spec->kctls.list);
10822
10823 add_verb(spec, alc883_auto_init_verbs);
10824 /* if ADC 0x07 is available, initialize it, too */
10825 if (get_wcaps_type(get_wcaps(codec, 0x07)) == AC_WID_AUD_IN)
10826 add_verb(spec, alc882_adc1_init_verbs);
10827
10828 spec->num_mux_defs = 1;
10829 spec->input_mux = &spec->private_imux[0];
10830
Kailang Yang6227cdc2010-02-25 08:36:52 +010010831 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai776e1842007-08-29 15:07:11 +020010832
10833 err = alc_auto_add_mic_boost(codec);
10834 if (err < 0)
10835 return err;
10836
Takashi Iwai776e1842007-08-29 15:07:11 +020010837 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010838}
10839
10840/* additional initialization for auto-configuration model */
Takashi Iwai49535502009-06-30 15:28:30 +020010841static void alc882_auto_init(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010842{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010843 struct alc_spec *spec = codec->spec;
Takashi Iwai49535502009-06-30 15:28:30 +020010844 alc882_auto_init_multi_out(codec);
10845 alc882_auto_init_hp_out(codec);
10846 alc882_auto_init_analog_input(codec);
10847 alc882_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020010848 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010849 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020010850 alc_inithook(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010851}
10852
Takashi Iwai49535502009-06-30 15:28:30 +020010853static int patch_alc882(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010854{
10855 struct alc_spec *spec;
10856 int err, board_config;
10857
10858 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
10859 if (spec == NULL)
10860 return -ENOMEM;
10861
10862 codec->spec = spec;
10863
Kailang Yangda00c242010-03-19 11:23:45 +010010864 alc_auto_parse_customize_define(codec);
10865
Takashi Iwai49535502009-06-30 15:28:30 +020010866 switch (codec->vendor_id) {
10867 case 0x10ec0882:
10868 case 0x10ec0885:
10869 break;
10870 default:
10871 /* ALC883 and variants */
10872 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
10873 break;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010874 }
10875
Takashi Iwai49535502009-06-30 15:28:30 +020010876 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
10877 alc882_models,
10878 alc882_cfg_tbl);
10879
10880 if (board_config < 0 || board_config >= ALC882_MODEL_LAST)
10881 board_config = snd_hda_check_board_codec_sid_config(codec,
10882 ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
10883
10884 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020010885 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai49535502009-06-30 15:28:30 +020010886 codec->chip_name);
10887 board_config = ALC882_AUTO;
10888 }
10889
Takashi Iwai7fa90e82010-04-12 08:49:00 +020010890 if (board_config == ALC882_AUTO)
10891 alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 1);
Takashi Iwai49535502009-06-30 15:28:30 +020010892
10893 if (board_config == ALC882_AUTO) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010894 /* automatic parse from the BIOS config */
Takashi Iwai49535502009-06-30 15:28:30 +020010895 err = alc882_parse_auto_config(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010896 if (err < 0) {
10897 alc_free(codec);
10898 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010899 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010900 printk(KERN_INFO
10901 "hda_codec: Cannot set up configuration "
10902 "from BIOS. Using base mode...\n");
Takashi Iwai49535502009-06-30 15:28:30 +020010903 board_config = ALC882_3ST_DIG;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010904 }
10905 }
10906
Takashi Iwaidc1eae22010-07-29 15:30:02 +020010907 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020010908 err = snd_hda_attach_beep_device(codec, 0x1);
10909 if (err < 0) {
10910 alc_free(codec);
10911 return err;
10912 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090010913 }
10914
Takashi Iwai49535502009-06-30 15:28:30 +020010915 if (board_config != ALC882_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020010916 setup_preset(codec, &alc882_presets[board_config]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010917
Takashi Iwai49535502009-06-30 15:28:30 +020010918 spec->stream_analog_playback = &alc882_pcm_analog_playback;
10919 spec->stream_analog_capture = &alc882_pcm_analog_capture;
10920 /* FIXME: setup DAC5 */
10921 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
10922 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
10923
10924 spec->stream_digital_playback = &alc882_pcm_digital_playback;
10925 spec->stream_digital_capture = &alc882_pcm_digital_capture;
10926
Takashi Iwai49535502009-06-30 15:28:30 +020010927 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010928 int i, j;
Takashi Iwai49535502009-06-30 15:28:30 +020010929 spec->num_adc_nids = 0;
10930 for (i = 0; i < ARRAY_SIZE(alc882_adc_nids); i++) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010931 const struct hda_input_mux *imux = spec->input_mux;
Takashi Iwai49535502009-06-30 15:28:30 +020010932 hda_nid_t cap;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010933 hda_nid_t items[16];
Takashi Iwai49535502009-06-30 15:28:30 +020010934 hda_nid_t nid = alc882_adc_nids[i];
10935 unsigned int wcap = get_wcaps(codec, nid);
10936 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020010937 wcap = get_wcaps_type(wcap);
Takashi Iwai49535502009-06-30 15:28:30 +020010938 if (wcap != AC_WID_AUD_IN)
10939 continue;
10940 spec->private_adc_nids[spec->num_adc_nids] = nid;
10941 err = snd_hda_get_connections(codec, nid, &cap, 1);
10942 if (err < 0)
10943 continue;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010944 err = snd_hda_get_connections(codec, cap, items,
10945 ARRAY_SIZE(items));
10946 if (err < 0)
10947 continue;
10948 for (j = 0; j < imux->num_items; j++)
10949 if (imux->items[j].index >= err)
10950 break;
10951 if (j < imux->num_items)
10952 continue;
Takashi Iwai49535502009-06-30 15:28:30 +020010953 spec->private_capsrc_nids[spec->num_adc_nids] = cap;
10954 spec->num_adc_nids++;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020010955 }
Takashi Iwai49535502009-06-30 15:28:30 +020010956 spec->adc_nids = spec->private_adc_nids;
10957 spec->capsrc_nids = spec->private_capsrc_nids;
Kailang Yang2f893282008-05-27 12:14:47 +020010958 }
10959
Takashi Iwaib59bdf32009-08-11 09:47:30 +020010960 set_capture_mixer(codec);
Kailang Yangda00c242010-03-19 11:23:45 +010010961
Takashi Iwaidc1eae22010-07-29 15:30:02 +020010962 if (has_cdefine_beep(codec))
Kailang Yangda00c242010-03-19 11:23:45 +010010963 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010964
Takashi Iwai7fa90e82010-04-12 08:49:00 +020010965 if (board_config == ALC882_AUTO)
10966 alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 0);
10967
Takashi Iwai2134ea42008-01-10 16:53:55 +010010968 spec->vmaster_nid = 0x0c;
10969
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010970 codec->patch_ops = alc_patch_ops;
Takashi Iwai49535502009-06-30 15:28:30 +020010971 if (board_config == ALC882_AUTO)
10972 spec->init_hook = alc882_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020010973#ifdef CONFIG_SND_HDA_POWER_SAVE
10974 if (!spec->loopback.amplist)
Takashi Iwai49535502009-06-30 15:28:30 +020010975 spec->loopback.amplist = alc882_loopbacks;
Takashi Iwaicb53c622007-08-10 17:21:45 +020010976#endif
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010977
10978 return 0;
10979}
10980
Takashi Iwai49535502009-06-30 15:28:30 +020010981
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010982/*
Kailang Yangdf694da2005-12-05 19:42:22 +010010983 * ALC262 support
10984 */
10985
10986#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
10987#define ALC262_DIGIN_NID ALC880_DIGIN_NID
10988
10989#define alc262_dac_nids alc260_dac_nids
10990#define alc262_adc_nids alc882_adc_nids
10991#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +010010992#define alc262_capsrc_nids alc882_capsrc_nids
10993#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +010010994
10995#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +010010996#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +010010997
Kailang Yang4e555fe2008-08-26 13:05:55 +020010998static hda_nid_t alc262_dmic_adc_nids[1] = {
10999 /* ADC0 */
11000 0x09
11001};
11002
11003static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
11004
Kailang Yangdf694da2005-12-05 19:42:22 +010011005static struct snd_kcontrol_new alc262_base_mixer[] = {
11006 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11007 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11008 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11009 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11010 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11011 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11012 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11013 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010011014 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011015 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11016 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010011017 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011018 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
11019 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11020 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
11021 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011022 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +010011023};
11024
Takashi Iwaice875f02008-01-28 18:17:43 +010011025/* update HP, line and mono-out pins according to the master switch */
11026static void alc262_hp_master_update(struct hda_codec *codec)
11027{
11028 struct alc_spec *spec = codec->spec;
11029 int val = spec->master_sw;
11030
11031 /* HP & line-out */
11032 snd_hda_codec_write_cache(codec, 0x1b, 0,
11033 AC_VERB_SET_PIN_WIDGET_CONTROL,
11034 val ? PIN_HP : 0);
11035 snd_hda_codec_write_cache(codec, 0x15, 0,
11036 AC_VERB_SET_PIN_WIDGET_CONTROL,
11037 val ? PIN_HP : 0);
11038 /* mono (speaker) depending on the HP jack sense */
11039 val = val && !spec->jack_present;
11040 snd_hda_codec_write_cache(codec, 0x16, 0,
11041 AC_VERB_SET_PIN_WIDGET_CONTROL,
11042 val ? PIN_OUT : 0);
11043}
11044
11045static void alc262_hp_bpc_automute(struct hda_codec *codec)
11046{
11047 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080011048
11049 spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
Takashi Iwaice875f02008-01-28 18:17:43 +010011050 alc262_hp_master_update(codec);
11051}
11052
11053static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
11054{
11055 if ((res >> 26) != ALC880_HP_EVENT)
11056 return;
11057 alc262_hp_bpc_automute(codec);
11058}
11059
11060static void alc262_hp_wildwest_automute(struct hda_codec *codec)
11061{
11062 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080011063
11064 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaice875f02008-01-28 18:17:43 +010011065 alc262_hp_master_update(codec);
11066}
11067
11068static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
11069 unsigned int res)
11070{
11071 if ((res >> 26) != ALC880_HP_EVENT)
11072 return;
11073 alc262_hp_wildwest_automute(codec);
11074}
11075
Takashi Iwaib72519b2009-05-08 14:31:55 +020011076#define alc262_hp_master_sw_get alc260_hp_master_sw_get
Takashi Iwaice875f02008-01-28 18:17:43 +010011077
11078static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
11079 struct snd_ctl_elem_value *ucontrol)
11080{
11081 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11082 struct alc_spec *spec = codec->spec;
11083 int val = !!*ucontrol->value.integer.value;
11084
11085 if (val == spec->master_sw)
11086 return 0;
11087 spec->master_sw = val;
11088 alc262_hp_master_update(codec);
11089 return 1;
11090}
11091
Takashi Iwaib72519b2009-05-08 14:31:55 +020011092#define ALC262_HP_MASTER_SWITCH \
11093 { \
11094 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
11095 .name = "Master Playback Switch", \
11096 .info = snd_ctl_boolean_mono_info, \
11097 .get = alc262_hp_master_sw_get, \
11098 .put = alc262_hp_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011099 }, \
11100 { \
11101 .iface = NID_MAPPING, \
11102 .name = "Master Playback Switch", \
11103 .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \
Takashi Iwaib72519b2009-05-08 14:31:55 +020011104 }
11105
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011106
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011107static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020011108 ALC262_HP_MASTER_SWITCH,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011109 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11110 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11111 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010011112 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
11113 HDA_OUTPUT),
11114 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
11115 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011116 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11117 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010011118 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011119 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11120 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010011121 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011122 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11123 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11124 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11125 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011126 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
11127 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
11128 { } /* end */
11129};
11130
Kailang Yangcd7509a2007-01-26 18:33:17 +010011131static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020011132 ALC262_HP_MASTER_SWITCH,
Kailang Yangcd7509a2007-01-26 18:33:17 +010011133 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11134 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
11135 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11136 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010011137 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
11138 HDA_OUTPUT),
11139 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
11140 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011141 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
11142 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010011143 HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011144 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
11145 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
11146 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11147 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011148 { } /* end */
11149};
11150
11151static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
11152 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11153 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010011154 HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011155 { } /* end */
11156};
11157
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011158/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011159static void alc262_hp_t5735_setup(struct hda_codec *codec)
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011160{
11161 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011162
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011163 spec->autocfg.hp_pins[0] = 0x15;
Takashi Iwaidc99be42010-01-20 08:35:06 +010011164 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011165}
11166
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011167static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010011168 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11169 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011170 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11171 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11172 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11173 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11174 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11175 { } /* end */
11176};
11177
11178static struct hda_verb alc262_hp_t5735_verbs[] = {
11179 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11180 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11181
11182 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11183 { }
11184};
11185
Kailang Yang8c427222008-01-10 13:03:59 +010011186static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +010011187 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11188 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010011189 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
11190 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010011191 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
11192 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
11193 { } /* end */
11194};
11195
11196static struct hda_verb alc262_hp_rp5700_verbs[] = {
11197 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11198 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11199 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11200 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11201 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11202 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11203 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11204 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11205 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
11206 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
11207 {}
11208};
11209
11210static struct hda_input_mux alc262_hp_rp5700_capture_source = {
11211 .num_items = 1,
11212 .items = {
11213 { "Line", 0x1 },
11214 },
11215};
11216
Takashi Iwai42171c12009-05-08 14:11:43 +020011217/* bind hp and internal speaker mute (with plug check) as master switch */
11218static void alc262_hippo_master_update(struct hda_codec *codec)
11219{
11220 struct alc_spec *spec = codec->spec;
11221 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
11222 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
11223 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
11224 unsigned int mute;
11225
11226 /* HP */
11227 mute = spec->master_sw ? 0 : HDA_AMP_MUTE;
11228 snd_hda_codec_amp_stereo(codec, hp_nid, HDA_OUTPUT, 0,
11229 HDA_AMP_MUTE, mute);
11230 /* mute internal speaker per jack sense */
11231 if (spec->jack_present)
11232 mute = HDA_AMP_MUTE;
11233 if (line_nid)
11234 snd_hda_codec_amp_stereo(codec, line_nid, HDA_OUTPUT, 0,
11235 HDA_AMP_MUTE, mute);
11236 if (speaker_nid && speaker_nid != line_nid)
11237 snd_hda_codec_amp_stereo(codec, speaker_nid, HDA_OUTPUT, 0,
11238 HDA_AMP_MUTE, mute);
11239}
11240
11241#define alc262_hippo_master_sw_get alc262_hp_master_sw_get
11242
11243static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol,
11244 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai0724ea22007-08-23 00:31:43 +020011245{
11246 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Takashi Iwai42171c12009-05-08 14:11:43 +020011247 struct alc_spec *spec = codec->spec;
11248 int val = !!*ucontrol->value.integer.value;
Takashi Iwai0724ea22007-08-23 00:31:43 +020011249
Takashi Iwai42171c12009-05-08 14:11:43 +020011250 if (val == spec->master_sw)
11251 return 0;
11252 spec->master_sw = val;
11253 alc262_hippo_master_update(codec);
11254 return 1;
Takashi Iwai0724ea22007-08-23 00:31:43 +020011255}
Takashi Iwai5b319542007-07-26 11:49:22 +020011256
Takashi Iwai42171c12009-05-08 14:11:43 +020011257#define ALC262_HIPPO_MASTER_SWITCH \
11258 { \
11259 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
11260 .name = "Master Playback Switch", \
11261 .info = snd_ctl_boolean_mono_info, \
11262 .get = alc262_hippo_master_sw_get, \
11263 .put = alc262_hippo_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011264 }, \
11265 { \
11266 .iface = NID_MAPPING, \
11267 .name = "Master Playback Switch", \
11268 .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \
11269 (SUBDEV_SPEAKER(0) << 16), \
Takashi Iwai42171c12009-05-08 14:11:43 +020011270 }
11271
11272static struct snd_kcontrol_new alc262_hippo_mixer[] = {
11273 ALC262_HIPPO_MASTER_SWITCH,
11274 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11275 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11276 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11277 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11278 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11279 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11280 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11281 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11282 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11283 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11284 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11285 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11286 { } /* end */
11287};
11288
11289static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
11290 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11291 ALC262_HIPPO_MASTER_SWITCH,
11292 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11293 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11294 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11295 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11296 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11297 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11298 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11299 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11300 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11301 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11302 { } /* end */
11303};
11304
11305/* mute/unmute internal speaker according to the hp jack and mute state */
11306static void alc262_hippo_automute(struct hda_codec *codec)
11307{
11308 struct alc_spec *spec = codec->spec;
11309 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
Takashi Iwai42171c12009-05-08 14:11:43 +020011310
Wu Fengguang864f92b2009-11-18 12:38:02 +080011311 spec->jack_present = snd_hda_jack_detect(codec, hp_nid);
Takashi Iwai42171c12009-05-08 14:11:43 +020011312 alc262_hippo_master_update(codec);
11313}
11314
11315static void alc262_hippo_unsol_event(struct hda_codec *codec, unsigned int res)
11316{
11317 if ((res >> 26) != ALC880_HP_EVENT)
11318 return;
11319 alc262_hippo_automute(codec);
11320}
11321
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011322static void alc262_hippo_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020011323{
11324 struct alc_spec *spec = codec->spec;
11325
11326 spec->autocfg.hp_pins[0] = 0x15;
11327 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai42171c12009-05-08 14:11:43 +020011328}
11329
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011330static void alc262_hippo1_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020011331{
11332 struct alc_spec *spec = codec->spec;
11333
11334 spec->autocfg.hp_pins[0] = 0x1b;
11335 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai42171c12009-05-08 14:11:43 +020011336}
11337
11338
Kailang Yang272a5272007-05-14 11:00:38 +020011339static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +020011340 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011341 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang272a5272007-05-14 11:00:38 +020011342 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11343 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11344 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11345 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11346 { } /* end */
11347};
11348
Kailang Yang83c34212007-07-05 11:43:05 +020011349static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011350 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11351 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang83c34212007-07-05 11:43:05 +020011352 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11353 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11354 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11355 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11356 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11357 { } /* end */
11358};
Kailang Yang272a5272007-05-14 11:00:38 +020011359
Tony Vroonba340e82009-02-02 19:01:30 +000011360static struct snd_kcontrol_new alc262_tyan_mixer[] = {
11361 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11362 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
11363 HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
11364 HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT),
11365 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11366 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11367 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11368 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11369 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11370 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11371 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11372 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11373 { } /* end */
11374};
11375
11376static struct hda_verb alc262_tyan_verbs[] = {
11377 /* Headphone automute */
11378 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11379 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11380 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11381
11382 /* P11 AUX_IN, white 4-pin connector */
11383 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11384 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
11385 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
11386 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
11387
11388 {}
11389};
11390
11391/* unsolicited event for HP jack sensing */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011392static void alc262_tyan_setup(struct hda_codec *codec)
Tony Vroonba340e82009-02-02 19:01:30 +000011393{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011394 struct alc_spec *spec = codec->spec;
Tony Vroonba340e82009-02-02 19:01:30 +000011395
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011396 spec->autocfg.hp_pins[0] = 0x1b;
11397 spec->autocfg.speaker_pins[0] = 0x15;
Tony Vroonba340e82009-02-02 19:01:30 +000011398}
11399
Tony Vroonba340e82009-02-02 19:01:30 +000011400
Kailang Yangdf694da2005-12-05 19:42:22 +010011401#define alc262_capture_mixer alc882_capture_mixer
11402#define alc262_capture_alt_mixer alc882_capture_alt_mixer
11403
11404/*
11405 * generic initialization of ADC, input mixers and output mixers
11406 */
11407static struct hda_verb alc262_init_verbs[] = {
11408 /*
11409 * Unmute ADC0-2 and set the default input to mic-in
11410 */
11411 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11412 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11413 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11414 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11415 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11416 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11417
Takashi Iwaicb53c622007-08-10 17:21:45 +020011418 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010011419 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011420 * Note: PASD motherboards uses the Line In 2 as the input for
11421 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010011422 */
11423 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011424 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11425 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11426 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11427 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11428 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011429
11430 /*
11431 * Set up output mixers (0x0c - 0x0e)
11432 */
11433 /* set vol=0 to output mixers */
11434 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11435 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11436 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11437 /* set up input amps for analog loopback */
11438 /* Amp Indices: DAC = 0, mixer = 1 */
11439 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11440 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11441 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11442 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11443 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11444 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11445
11446 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11447 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11448 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11449 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11450 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11451 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11452
11453 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11454 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11455 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11456 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11457 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Kailang Yangea1fb292008-08-26 12:58:38 +020011458
Kailang Yangdf694da2005-12-05 19:42:22 +010011459 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11460 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Kailang Yangea1fb292008-08-26 12:58:38 +020011461
Kailang Yangdf694da2005-12-05 19:42:22 +010011462 /* FIXME: use matrix-type input source selection */
11463 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
11464 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
11465 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11466 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11467 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11468 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11469 /* Input mixer2 */
11470 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11471 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11472 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11473 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11474 /* Input mixer3 */
11475 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11476 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11477 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011478 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +010011479
11480 { }
11481};
11482
Kailang Yang4e555fe2008-08-26 13:05:55 +020011483static struct hda_verb alc262_eapd_verbs[] = {
11484 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
11485 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
11486 { }
11487};
11488
Kailang Yangccc656c2006-10-17 12:32:26 +020011489static struct hda_verb alc262_hippo1_unsol_verbs[] = {
11490 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11491 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11492 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11493
11494 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11495 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11496 {}
11497};
11498
Kailang Yang272a5272007-05-14 11:00:38 +020011499static struct hda_verb alc262_sony_unsol_verbs[] = {
11500 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11501 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11502 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
11503
11504 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11505 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +090011506 {}
Kailang Yang272a5272007-05-14 11:00:38 +020011507};
11508
Kailang Yang4e555fe2008-08-26 13:05:55 +020011509static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
11510 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11511 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11512 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11513 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11514 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang4e555fe2008-08-26 13:05:55 +020011515 { } /* end */
11516};
11517
11518static struct hda_verb alc262_toshiba_s06_verbs[] = {
11519 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11520 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11521 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11522 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11523 {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
11524 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11525 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11526 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11527 {}
11528};
11529
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011530static void alc262_toshiba_s06_setup(struct hda_codec *codec)
Kailang Yang4e555fe2008-08-26 13:05:55 +020011531{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011532 struct alc_spec *spec = codec->spec;
11533
11534 spec->autocfg.hp_pins[0] = 0x15;
11535 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011536 spec->ext_mic.pin = 0x18;
11537 spec->ext_mic.mux_idx = 0;
11538 spec->int_mic.pin = 0x12;
11539 spec->int_mic.mux_idx = 9;
11540 spec->auto_mic = 1;
Kailang Yang4e555fe2008-08-26 13:05:55 +020011541}
11542
Takashi Iwai834be882006-03-01 14:16:17 +010011543/*
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011544 * nec model
11545 * 0x15 = headphone
11546 * 0x16 = internal speaker
11547 * 0x18 = external mic
11548 */
11549
11550static struct snd_kcontrol_new alc262_nec_mixer[] = {
11551 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
11552 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
11553
11554 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11555 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11556 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11557
11558 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11559 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11560 { } /* end */
11561};
11562
11563static struct hda_verb alc262_nec_verbs[] = {
11564 /* Unmute Speaker */
11565 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11566
11567 /* Headphone */
11568 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11569 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11570
11571 /* External mic to headphone */
11572 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11573 /* External mic to speaker */
11574 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11575 {}
11576};
11577
11578/*
Takashi Iwai834be882006-03-01 14:16:17 +010011579 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +010011580 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
11581 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +010011582 */
11583
11584#define ALC_HP_EVENT 0x37
11585
11586static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
11587 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11588 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +010011589 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11590 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +010011591 {}
11592};
11593
Jiang zhe0e31daf2008-03-20 12:12:39 +010011594static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
11595 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11596 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11597 {}
11598};
11599
Daniel T Chene2595322009-12-19 18:19:02 -050011600static struct hda_verb alc262_lenovo_3000_init_verbs[] = {
11601 /* Front Mic pin: input vref at 50% */
11602 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
11603 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11604 {}
11605};
11606
Takashi Iwai834be882006-03-01 14:16:17 +010011607static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011608 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +010011609 .items = {
11610 { "Mic", 0x0 },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011611 { "Int Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +010011612 { "CD", 0x4 },
11613 },
11614};
11615
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011616static struct hda_input_mux alc262_HP_capture_source = {
11617 .num_items = 5,
11618 .items = {
11619 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +020011620 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011621 { "Line", 0x2 },
11622 { "CD", 0x4 },
11623 { "AUX IN", 0x6 },
11624 },
11625};
11626
zhejiangaccbe492007-08-31 12:36:05 +020011627static struct hda_input_mux alc262_HP_D7000_capture_source = {
11628 .num_items = 4,
11629 .items = {
11630 { "Mic", 0x0 },
11631 { "Front Mic", 0x2 },
11632 { "Line", 0x1 },
11633 { "CD", 0x4 },
11634 },
11635};
11636
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011637/* mute/unmute internal speaker according to the hp jacks and mute state */
Takashi Iwai834be882006-03-01 14:16:17 +010011638static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
11639{
11640 struct alc_spec *spec = codec->spec;
11641 unsigned int mute;
11642
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011643 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011644 spec->jack_present = snd_hda_jack_detect(codec, 0x14) ||
11645 snd_hda_jack_detect(codec, 0x1b);
Takashi Iwai834be882006-03-01 14:16:17 +010011646 spec->sense_updated = 1;
11647 }
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011648 /* unmute internal speaker only if both HPs are unplugged and
11649 * master switch is on
11650 */
11651 if (spec->jack_present)
11652 mute = HDA_AMP_MUTE;
11653 else
Takashi Iwai834be882006-03-01 14:16:17 +010011654 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011655 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
11656 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +010011657}
11658
11659/* unsolicited event for HP jack sensing */
11660static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
11661 unsigned int res)
11662{
11663 if ((res >> 26) != ALC_HP_EVENT)
11664 return;
11665 alc262_fujitsu_automute(codec, 1);
11666}
11667
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011668static void alc262_fujitsu_init_hook(struct hda_codec *codec)
11669{
11670 alc262_fujitsu_automute(codec, 1);
11671}
11672
Takashi Iwai834be882006-03-01 14:16:17 +010011673/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +020011674static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
11675 .ops = &snd_hda_bind_vol,
11676 .values = {
11677 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
11678 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
11679 0
11680 },
11681};
Takashi Iwai834be882006-03-01 14:16:17 +010011682
Jiang zhe0e31daf2008-03-20 12:12:39 +010011683/* mute/unmute internal speaker according to the hp jack and mute state */
11684static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
11685{
11686 struct alc_spec *spec = codec->spec;
11687 unsigned int mute;
11688
11689 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011690 spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
Jiang zhe0e31daf2008-03-20 12:12:39 +010011691 spec->sense_updated = 1;
11692 }
11693 if (spec->jack_present) {
11694 /* mute internal speaker */
11695 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11696 HDA_AMP_MUTE, HDA_AMP_MUTE);
11697 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
11698 HDA_AMP_MUTE, HDA_AMP_MUTE);
11699 } else {
11700 /* unmute internal speaker if necessary */
11701 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
11702 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11703 HDA_AMP_MUTE, mute);
11704 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
11705 HDA_AMP_MUTE, mute);
11706 }
11707}
11708
11709/* unsolicited event for HP jack sensing */
11710static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
11711 unsigned int res)
11712{
11713 if ((res >> 26) != ALC_HP_EVENT)
11714 return;
11715 alc262_lenovo_3000_automute(codec, 1);
11716}
11717
Takashi Iwai8de56b72009-07-24 16:51:47 +020011718static int amp_stereo_mute_update(struct hda_codec *codec, hda_nid_t nid,
11719 int dir, int idx, long *valp)
11720{
11721 int i, change = 0;
11722
11723 for (i = 0; i < 2; i++, valp++)
11724 change |= snd_hda_codec_amp_update(codec, nid, i, dir, idx,
11725 HDA_AMP_MUTE,
11726 *valp ? 0 : HDA_AMP_MUTE);
11727 return change;
11728}
11729
Takashi Iwai834be882006-03-01 14:16:17 +010011730/* bind hp and internal speaker mute (with plug check) */
11731static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
11732 struct snd_ctl_elem_value *ucontrol)
11733{
11734 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11735 long *valp = ucontrol->value.integer.value;
11736 int change;
11737
Takashi Iwai8de56b72009-07-24 16:51:47 +020011738 change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
11739 change |= amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
Takashi Iwai82beb8f2007-08-10 17:09:26 +020011740 if (change)
11741 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +010011742 return change;
11743}
11744
11745static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +020011746 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +010011747 {
11748 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11749 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010011750 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwai834be882006-03-01 14:16:17 +010011751 .info = snd_hda_mixer_amp_switch_info,
11752 .get = snd_hda_mixer_amp_switch_get,
11753 .put = alc262_fujitsu_master_sw_put,
11754 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11755 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011756 {
11757 .iface = NID_MAPPING,
11758 .name = "Master Playback Switch",
11759 .private_value = 0x1b,
11760 },
Takashi Iwai834be882006-03-01 14:16:17 +010011761 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11762 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11763 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11764 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11765 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011766 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
11767 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11768 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010011769 { } /* end */
11770};
11771
Jiang zhe0e31daf2008-03-20 12:12:39 +010011772/* bind hp and internal speaker mute (with plug check) */
11773static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
11774 struct snd_ctl_elem_value *ucontrol)
11775{
11776 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11777 long *valp = ucontrol->value.integer.value;
11778 int change;
11779
Takashi Iwai8de56b72009-07-24 16:51:47 +020011780 change = amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
Jiang zhe0e31daf2008-03-20 12:12:39 +010011781 if (change)
11782 alc262_lenovo_3000_automute(codec, 0);
11783 return change;
11784}
11785
11786static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
11787 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
11788 {
11789 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11790 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010011791 .subdevice = HDA_SUBDEV_AMP_FLAG,
Jiang zhe0e31daf2008-03-20 12:12:39 +010011792 .info = snd_hda_mixer_amp_switch_info,
11793 .get = snd_hda_mixer_amp_switch_get,
11794 .put = alc262_lenovo_3000_master_sw_put,
11795 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
11796 },
11797 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11798 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11799 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11800 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11801 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11802 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
11803 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11804 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
11805 { } /* end */
11806};
11807
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011808static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
11809 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai42171c12009-05-08 14:11:43 +020011810 ALC262_HIPPO_MASTER_SWITCH,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011811 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11812 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11813 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11814 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11815 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11816 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11817 { } /* end */
11818};
11819
Takashi Iwai304dcaa2006-07-25 14:51:16 +020011820/* additional init verbs for Benq laptops */
11821static struct hda_verb alc262_EAPD_verbs[] = {
11822 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
11823 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
11824 {}
11825};
11826
Kailang Yang83c34212007-07-05 11:43:05 +020011827static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
11828 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11829 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11830
11831 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
11832 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
11833 {}
11834};
11835
Tobin Davisf651b502007-10-26 12:40:47 +020011836/* Samsung Q1 Ultra Vista model setup */
11837static struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011838 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11839 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020011840 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11841 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11842 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011843 HDA_CODEC_VOLUME("Headphone Mic Boost", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020011844 { } /* end */
11845};
11846
11847static struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011848 /* output mixer */
11849 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11850 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11851 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11852 /* speaker */
11853 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11854 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11855 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11856 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11857 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +020011858 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011859 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11860 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11861 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11862 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11863 /* internal mic */
11864 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11865 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11866 /* ADC, choose mic */
11867 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11868 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11869 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11870 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11871 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11872 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11873 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
11874 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
11875 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
11876 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +020011877 {}
11878};
11879
Tobin Davisf651b502007-10-26 12:40:47 +020011880/* mute/unmute internal speaker according to the hp jack and mute state */
11881static void alc262_ultra_automute(struct hda_codec *codec)
11882{
11883 struct alc_spec *spec = codec->spec;
11884 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +020011885
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011886 mute = 0;
11887 /* auto-mute only when HP is used as HP */
11888 if (!spec->cur_mux[0]) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011889 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011890 if (spec->jack_present)
11891 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +020011892 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011893 /* mute/unmute internal speaker */
11894 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11895 HDA_AMP_MUTE, mute);
11896 /* mute/unmute HP */
11897 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
11898 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +020011899}
11900
11901/* unsolicited event for HP jack sensing */
11902static void alc262_ultra_unsol_event(struct hda_codec *codec,
11903 unsigned int res)
11904{
11905 if ((res >> 26) != ALC880_HP_EVENT)
11906 return;
11907 alc262_ultra_automute(codec);
11908}
11909
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011910static struct hda_input_mux alc262_ultra_capture_source = {
11911 .num_items = 2,
11912 .items = {
11913 { "Mic", 0x1 },
11914 { "Headphone", 0x7 },
11915 },
11916};
11917
11918static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
11919 struct snd_ctl_elem_value *ucontrol)
11920{
11921 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11922 struct alc_spec *spec = codec->spec;
11923 int ret;
11924
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011925 ret = alc_mux_enum_put(kcontrol, ucontrol);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011926 if (!ret)
11927 return 0;
11928 /* reprogram the HP pin as mic or HP according to the input source */
11929 snd_hda_codec_write_cache(codec, 0x15, 0,
11930 AC_VERB_SET_PIN_WIDGET_CONTROL,
11931 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
11932 alc262_ultra_automute(codec); /* mute/unmute HP */
11933 return ret;
11934}
11935
11936static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
11937 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
11938 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
11939 {
11940 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11941 .name = "Capture Source",
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011942 .info = alc_mux_enum_info,
11943 .get = alc_mux_enum_get,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011944 .put = alc262_ultra_mux_enum_put,
11945 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011946 {
11947 .iface = NID_MAPPING,
11948 .name = "Capture Source",
11949 .private_value = 0x15,
11950 },
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011951 { } /* end */
11952};
11953
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011954/* We use two mixers depending on the output pin; 0x16 is a mono output
11955 * and thus it's bound with a different mixer.
11956 * This function returns which mixer amp should be used.
11957 */
11958static int alc262_check_volbit(hda_nid_t nid)
11959{
11960 if (!nid)
11961 return 0;
11962 else if (nid == 0x16)
11963 return 2;
11964 else
11965 return 1;
11966}
11967
11968static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai033688a2010-09-08 15:47:09 +020011969 const char *pfx, int *vbits, int idx)
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011970{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011971 unsigned long val;
11972 int vbit;
11973
11974 vbit = alc262_check_volbit(nid);
11975 if (!vbit)
11976 return 0;
11977 if (*vbits & vbit) /* a volume control for this mixer already there */
11978 return 0;
11979 *vbits |= vbit;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011980 if (vbit == 2)
11981 val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT);
11982 else
11983 val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT);
Takashi Iwai033688a2010-09-08 15:47:09 +020011984 return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011985}
11986
11987static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai033688a2010-09-08 15:47:09 +020011988 const char *pfx, int idx)
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011989{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011990 unsigned long val;
11991
11992 if (!nid)
11993 return 0;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011994 if (nid == 0x16)
11995 val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
11996 else
11997 val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
Takashi Iwai033688a2010-09-08 15:47:09 +020011998 return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011999}
12000
Kailang Yangdf694da2005-12-05 19:42:22 +010012001/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012002static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
12003 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010012004{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012005 const char *pfx;
12006 int vbits;
Takashi Iwai033688a2010-09-08 15:47:09 +020012007 int i, err;
Kailang Yangdf694da2005-12-05 19:42:22 +010012008
12009 spec->multiout.num_dacs = 1; /* only use one dac */
12010 spec->multiout.dac_nids = spec->private_dac_nids;
12011 spec->multiout.dac_nids[0] = 2;
12012
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012013 if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
12014 pfx = "Master";
12015 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
12016 pfx = "Speaker";
Takashi Iwai033688a2010-09-08 15:47:09 +020012017 else if (cfg->line_out_type == AUTO_PIN_HP_OUT)
12018 pfx = "Headphone";
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012019 else
12020 pfx = "Front";
Takashi Iwai033688a2010-09-08 15:47:09 +020012021 for (i = 0; i < 2; i++) {
12022 err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[i], pfx, i);
12023 if (err < 0)
12024 return err;
12025 if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
12026 err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[i],
12027 "Speaker", i);
12028 if (err < 0)
12029 return err;
12030 }
12031 if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
12032 err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[i],
12033 "Headphone", i);
12034 if (err < 0)
12035 return err;
12036 }
12037 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012038
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012039 vbits = alc262_check_volbit(cfg->line_out_pins[0]) |
12040 alc262_check_volbit(cfg->speaker_pins[0]) |
12041 alc262_check_volbit(cfg->hp_pins[0]);
12042 if (vbits == 1 || vbits == 2)
12043 pfx = "Master"; /* only one mixer is used */
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012044 vbits = 0;
Takashi Iwai033688a2010-09-08 15:47:09 +020012045 for (i = 0; i < 2; i++) {
12046 err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[i], pfx,
12047 &vbits, i);
12048 if (err < 0)
12049 return err;
12050 if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
12051 err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[i],
12052 "Speaker", &vbits, i);
12053 if (err < 0)
12054 return err;
12055 }
12056 if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
12057 err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[i],
12058 "Headphone", &vbits, i);
12059 if (err < 0)
12060 return err;
12061 }
12062 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012063 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +010012064}
12065
Takashi Iwai05f5f472009-08-25 13:10:18 +020012066#define alc262_auto_create_input_ctls \
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +010012067 alc882_auto_create_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +010012068
12069/*
12070 * generic initialization of ADC, input mixers and output mixers
12071 */
12072static struct hda_verb alc262_volume_init_verbs[] = {
12073 /*
12074 * Unmute ADC0-2 and set the default input to mic-in
12075 */
12076 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
12077 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12078 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12079 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12080 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12081 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12082
Takashi Iwaicb53c622007-08-10 17:21:45 +020012083 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010012084 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012085 * Note: PASD motherboards uses the Line In 2 as the input for
12086 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010012087 */
12088 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012089 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12090 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12091 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12092 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12093 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012094
12095 /*
12096 * Set up output mixers (0x0c - 0x0f)
12097 */
12098 /* set vol=0 to output mixers */
12099 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12100 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12101 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yangea1fb292008-08-26 12:58:38 +020012102
Kailang Yangdf694da2005-12-05 19:42:22 +010012103 /* set up input amps for analog loopback */
12104 /* Amp Indices: DAC = 0, mixer = 1 */
12105 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12106 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12107 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12108 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12109 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12110 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12111
12112 /* FIXME: use matrix-type input source selection */
12113 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
12114 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
12115 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12116 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12117 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12118 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12119 /* Input mixer2 */
12120 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12121 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12122 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12123 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12124 /* Input mixer3 */
12125 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12126 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12127 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12128 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12129
12130 { }
12131};
12132
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012133static struct hda_verb alc262_HP_BPC_init_verbs[] = {
12134 /*
12135 * Unmute ADC0-2 and set the default input to mic-in
12136 */
12137 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
12138 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12139 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12140 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12141 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12142 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12143
Takashi Iwaicb53c622007-08-10 17:21:45 +020012144 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012145 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012146 * Note: PASD motherboards uses the Line In 2 as the input for
12147 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012148 */
12149 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012150 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12151 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12152 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12153 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12154 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12155 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12156 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012157
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012158 /*
12159 * Set up output mixers (0x0c - 0x0e)
12160 */
12161 /* set vol=0 to output mixers */
12162 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12163 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12164 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12165
12166 /* set up input amps for analog loopback */
12167 /* Amp Indices: DAC = 0, mixer = 1 */
12168 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12169 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12170 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12171 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12172 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12173 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12174
Takashi Iwaice875f02008-01-28 18:17:43 +010012175 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012176 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12177 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12178
12179 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12180 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12181
12182 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12183 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12184
12185 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12186 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12187 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12188 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12189 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12190
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012191 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012192 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12193 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012194 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012195 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12196 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12197
12198
12199 /* FIXME: use matrix-type input source selection */
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012200 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */
12201 /* Input mixer1: only unmute Mic */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012202 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012203 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12204 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12205 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12206 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12207 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12208 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12209 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12210 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012211 /* Input mixer2 */
12212 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012213 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12214 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12215 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12216 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12217 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12218 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12219 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12220 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012221 /* Input mixer3 */
12222 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012223 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12224 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12225 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12226 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12227 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12228 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12229 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12230 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012231
Takashi Iwaice875f02008-01-28 18:17:43 +010012232 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12233
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012234 { }
12235};
12236
Kailang Yangcd7509a2007-01-26 18:33:17 +010012237static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
12238 /*
12239 * Unmute ADC0-2 and set the default input to mic-in
12240 */
12241 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
12242 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12243 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12244 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12245 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12246 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12247
Takashi Iwaicb53c622007-08-10 17:21:45 +020012248 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +010012249 * mixer widget
12250 * Note: PASD motherboards uses the Line In 2 as the input for front
12251 * panel mic (mic 2)
12252 */
12253 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012254 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12255 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12256 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12257 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12258 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12259 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12260 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
12261 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +010012262 /*
12263 * Set up output mixers (0x0c - 0x0e)
12264 */
12265 /* set vol=0 to output mixers */
12266 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12267 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12268 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12269
12270 /* set up input amps for analog loopback */
12271 /* Amp Indices: DAC = 0, mixer = 1 */
12272 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12273 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12274 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12275 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12276 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12277 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12278
12279
12280 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
12281 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
12282 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
12283 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
12284 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
12285 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
12286 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
12287
12288 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12289 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12290
12291 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12292 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12293
12294 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
12295 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12296 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12297 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
12298 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12299 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12300
12301 /* FIXME: use matrix-type input source selection */
12302 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
12303 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
12304 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
12305 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
12306 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
12307 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
12308 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
12309 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12310 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
12311 /* Input mixer2 */
12312 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12313 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
12314 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
12315 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
12316 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
12317 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12318 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
12319 /* Input mixer3 */
12320 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12321 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
12322 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
12323 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
12324 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
12325 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12326 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
12327
Takashi Iwaice875f02008-01-28 18:17:43 +010012328 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12329
Kailang Yangcd7509a2007-01-26 18:33:17 +010012330 { }
12331};
12332
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012333static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
12334
12335 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */
12336 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12337 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
12338
12339 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */
12340 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
12341 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
12342 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
12343
12344 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */
12345 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12346 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12347 {}
12348};
12349
Takashi Iwai18675e42010-09-08 15:55:44 +020012350/*
12351 * Pin config fixes
12352 */
12353enum {
12354 PINFIX_FSC_H270,
12355};
12356
12357static const struct alc_fixup alc262_fixups[] = {
12358 [PINFIX_FSC_H270] = {
12359 .pins = (const struct alc_pincfg[]) {
12360 { 0x14, 0x99130110 }, /* speaker */
12361 { 0x15, 0x0221142f }, /* front HP */
12362 { 0x1b, 0x0121141f }, /* rear HP */
12363 { }
12364 }
12365 },
12366 [PINFIX_PB_M5210] = {
12367 .verbs = (const struct hda_verb[]) {
12368 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
12369 {}
12370 }
12371 },
12372};
12373
12374static struct snd_pci_quirk alc262_fixup_tbl[] = {
12375 SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270),
12376 {}
12377};
12378
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012379
Takashi Iwaicb53c622007-08-10 17:21:45 +020012380#ifdef CONFIG_SND_HDA_POWER_SAVE
12381#define alc262_loopbacks alc880_loopbacks
12382#endif
12383
Sasha Alexandrdef319f2009-06-16 16:00:15 -040012384/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012385#define alc262_pcm_analog_playback alc880_pcm_analog_playback
12386#define alc262_pcm_analog_capture alc880_pcm_analog_capture
12387#define alc262_pcm_digital_playback alc880_pcm_digital_playback
12388#define alc262_pcm_digital_capture alc880_pcm_digital_capture
12389
12390/*
12391 * BIOS auto configuration
12392 */
12393static int alc262_parse_auto_config(struct hda_codec *codec)
12394{
12395 struct alc_spec *spec = codec->spec;
12396 int err;
12397 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
12398
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012399 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12400 alc262_ignore);
12401 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012402 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012403 if (!spec->autocfg.line_outs) {
Takashi Iwai0852d7a2009-02-11 11:35:15 +010012404 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012405 spec->multiout.max_channels = 2;
12406 spec->no_analog = 1;
12407 goto dig_only;
12408 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012409 return 0; /* can't find valid BIOS pin config */
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012410 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012411 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
12412 if (err < 0)
12413 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020012414 err = alc262_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012415 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012416 return err;
12417
12418 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12419
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012420 dig_only:
Takashi Iwai757899a2010-07-30 10:48:14 +020012421 alc_auto_parse_digital(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012422
Takashi Iwai603c4012008-07-30 15:01:44 +020012423 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012424 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010012425
Takashi Iwaid88897e2008-10-31 15:01:37 +010012426 add_verb(spec, alc262_volume_init_verbs);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020012427 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020012428 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010012429
Takashi Iwai776e1842007-08-29 15:07:11 +020012430 err = alc_auto_add_mic_boost(codec);
12431 if (err < 0)
12432 return err;
12433
Kailang Yang6227cdc2010-02-25 08:36:52 +010012434 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020012435
Kailang Yangdf694da2005-12-05 19:42:22 +010012436 return 1;
12437}
12438
12439#define alc262_auto_init_multi_out alc882_auto_init_multi_out
12440#define alc262_auto_init_hp_out alc882_auto_init_hp_out
12441#define alc262_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaif511b012008-08-15 16:46:42 +020012442#define alc262_auto_init_input_src alc882_auto_init_input_src
Kailang Yangdf694da2005-12-05 19:42:22 +010012443
12444
12445/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012446static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010012447{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012448 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010012449 alc262_auto_init_multi_out(codec);
12450 alc262_auto_init_hp_out(codec);
12451 alc262_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020012452 alc262_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020012453 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012454 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020012455 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012456}
12457
12458/*
12459 * configuration and preset
12460 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012461static const char *alc262_models[ALC262_MODEL_LAST] = {
12462 [ALC262_BASIC] = "basic",
12463 [ALC262_HIPPO] = "hippo",
12464 [ALC262_HIPPO_1] = "hippo_1",
12465 [ALC262_FUJITSU] = "fujitsu",
12466 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +010012467 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +010012468 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +010012469 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012470 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +020012471 [ALC262_BENQ_T31] = "benq-t31",
12472 [ALC262_SONY_ASSAMD] = "sony-assamd",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020012473 [ALC262_TOSHIBA_S06] = "toshiba-s06",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012474 [ALC262_TOSHIBA_RX1] = "toshiba-rx1",
Tobin Davisf651b502007-10-26 12:40:47 +020012475 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +010012476 [ALC262_LENOVO_3000] = "lenovo-3000",
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012477 [ALC262_NEC] = "nec",
Tony Vroonba340e82009-02-02 19:01:30 +000012478 [ALC262_TYAN] = "tyan",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012479 [ALC262_AUTO] = "auto",
12480};
12481
12482static struct snd_pci_quirk alc262_cfg_tbl[] = {
12483 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012484 SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
Takashi Iwaidea0a502009-02-09 17:14:52 +010012485 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
12486 ALC262_HP_BPC),
12487 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series",
12488 ALC262_HP_BPC),
Takashi Iwai53eff7e2009-02-27 17:49:44 +010012489 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
12490 ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012491 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012492 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012493 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012494 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012495 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012496 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012497 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012498 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012499 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
12500 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
12501 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012502 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
12503 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +010012504 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012505 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012506 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012507 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaibd6afe32009-03-04 11:30:25 +010012508 SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */
Takashi Iwai376b5082009-06-22 11:03:13 +020012509 SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06),
Daniel T Chen95491d92009-11-08 19:03:55 -050012510 SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO),
Takashi Iwai12929ba2009-11-17 15:58:35 +010012511 SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO),
Takashi Iwaic5b51652009-11-17 16:01:58 +010012512#if 0 /* disable the quirk since model=auto works better in recent versions */
Takashi Iwaif872a912009-02-26 00:57:01 +010012513 SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
12514 ALC262_SONY_ASSAMD),
Takashi Iwaic5b51652009-11-17 16:01:58 +010012515#endif
Akio Idehara36ca6e12008-06-09 22:57:40 +090012516 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012517 ALC262_TOSHIBA_RX1),
Kailang Yang80ffe862008-10-15 11:23:27 +020012518 SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012519 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +010012520 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Tony Vroonba340e82009-02-02 19:01:30 +000012521 SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
Takashi Iwaidea0a502009-02-09 17:14:52 +010012522 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1",
12523 ALC262_ULTRA),
Luke Yelavich3e420e72008-12-16 12:37:47 +110012524 SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
Jiang zhe0e31daf2008-03-20 12:12:39 +010012525 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012526 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +020012527 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012528 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +010012529 {}
12530};
12531
12532static struct alc_config_preset alc262_presets[] = {
12533 [ALC262_BASIC] = {
12534 .mixers = { alc262_base_mixer },
12535 .init_verbs = { alc262_init_verbs },
12536 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12537 .dac_nids = alc262_dac_nids,
12538 .hp_nid = 0x03,
12539 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12540 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +010012541 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +010012542 },
Kailang Yangccc656c2006-10-17 12:32:26 +020012543 [ALC262_HIPPO] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020012544 .mixers = { alc262_hippo_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020012545 .init_verbs = { alc262_init_verbs, alc_hp15_unsol_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020012546 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12547 .dac_nids = alc262_dac_nids,
12548 .hp_nid = 0x03,
12549 .dig_out_nid = ALC262_DIGOUT_NID,
12550 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12551 .channel_mode = alc262_modes,
12552 .input_mux = &alc262_capture_source,
12553 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012554 .setup = alc262_hippo_setup,
12555 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020012556 },
12557 [ALC262_HIPPO_1] = {
12558 .mixers = { alc262_hippo1_mixer },
12559 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
12560 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12561 .dac_nids = alc262_dac_nids,
12562 .hp_nid = 0x02,
12563 .dig_out_nid = ALC262_DIGOUT_NID,
12564 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12565 .channel_mode = alc262_modes,
12566 .input_mux = &alc262_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020012567 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012568 .setup = alc262_hippo1_setup,
12569 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020012570 },
Takashi Iwai834be882006-03-01 14:16:17 +010012571 [ALC262_FUJITSU] = {
12572 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020012573 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
12574 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +010012575 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12576 .dac_nids = alc262_dac_nids,
12577 .hp_nid = 0x03,
12578 .dig_out_nid = ALC262_DIGOUT_NID,
12579 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12580 .channel_mode = alc262_modes,
12581 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012582 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwaiebc7a402008-05-20 09:23:05 +020012583 .init_hook = alc262_fujitsu_init_hook,
Takashi Iwai834be882006-03-01 14:16:17 +010012584 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012585 [ALC262_HP_BPC] = {
12586 .mixers = { alc262_HP_BPC_mixer },
12587 .init_verbs = { alc262_HP_BPC_init_verbs },
12588 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12589 .dac_nids = alc262_dac_nids,
12590 .hp_nid = 0x03,
12591 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12592 .channel_mode = alc262_modes,
12593 .input_mux = &alc262_HP_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010012594 .unsol_event = alc262_hp_bpc_unsol_event,
12595 .init_hook = alc262_hp_bpc_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012596 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010012597 [ALC262_HP_BPC_D7000_WF] = {
12598 .mixers = { alc262_HP_BPC_WildWest_mixer },
12599 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
12600 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12601 .dac_nids = alc262_dac_nids,
12602 .hp_nid = 0x03,
12603 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12604 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020012605 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010012606 .unsol_event = alc262_hp_wildwest_unsol_event,
12607 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012608 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010012609 [ALC262_HP_BPC_D7000_WL] = {
12610 .mixers = { alc262_HP_BPC_WildWest_mixer,
12611 alc262_HP_BPC_WildWest_option_mixer },
12612 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
12613 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12614 .dac_nids = alc262_dac_nids,
12615 .hp_nid = 0x03,
12616 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12617 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020012618 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010012619 .unsol_event = alc262_hp_wildwest_unsol_event,
12620 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012621 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012622 [ALC262_HP_TC_T5735] = {
12623 .mixers = { alc262_hp_t5735_mixer },
12624 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
12625 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12626 .dac_nids = alc262_dac_nids,
12627 .hp_nid = 0x03,
12628 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12629 .channel_mode = alc262_modes,
12630 .input_mux = &alc262_capture_source,
Takashi Iwaidc99be42010-01-20 08:35:06 +010012631 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012632 .setup = alc262_hp_t5735_setup,
Takashi Iwaidc99be42010-01-20 08:35:06 +010012633 .init_hook = alc_inithook,
Kailang Yang8c427222008-01-10 13:03:59 +010012634 },
12635 [ALC262_HP_RP5700] = {
12636 .mixers = { alc262_hp_rp5700_mixer },
12637 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
12638 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12639 .dac_nids = alc262_dac_nids,
12640 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12641 .channel_mode = alc262_modes,
12642 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012643 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +020012644 [ALC262_BENQ_ED8] = {
12645 .mixers = { alc262_base_mixer },
12646 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
12647 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12648 .dac_nids = alc262_dac_nids,
12649 .hp_nid = 0x03,
12650 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12651 .channel_mode = alc262_modes,
12652 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012653 },
Kailang Yang272a5272007-05-14 11:00:38 +020012654 [ALC262_SONY_ASSAMD] = {
12655 .mixers = { alc262_sony_mixer },
12656 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
12657 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12658 .dac_nids = alc262_dac_nids,
12659 .hp_nid = 0x02,
12660 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12661 .channel_mode = alc262_modes,
12662 .input_mux = &alc262_capture_source,
12663 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012664 .setup = alc262_hippo_setup,
12665 .init_hook = alc262_hippo_automute,
Kailang Yang83c34212007-07-05 11:43:05 +020012666 },
12667 [ALC262_BENQ_T31] = {
12668 .mixers = { alc262_benq_t31_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020012669 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs,
12670 alc_hp15_unsol_verbs },
Kailang Yang83c34212007-07-05 11:43:05 +020012671 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12672 .dac_nids = alc262_dac_nids,
12673 .hp_nid = 0x03,
12674 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12675 .channel_mode = alc262_modes,
12676 .input_mux = &alc262_capture_source,
12677 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012678 .setup = alc262_hippo_setup,
12679 .init_hook = alc262_hippo_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020012680 },
Tobin Davisf651b502007-10-26 12:40:47 +020012681 [ALC262_ULTRA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012682 .mixers = { alc262_ultra_mixer },
12683 .cap_mixer = alc262_ultra_capture_mixer,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012684 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +020012685 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12686 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +020012687 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12688 .channel_mode = alc262_modes,
12689 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012690 .adc_nids = alc262_adc_nids, /* ADC0 */
12691 .capsrc_nids = alc262_capsrc_nids,
12692 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +020012693 .unsol_event = alc262_ultra_unsol_event,
12694 .init_hook = alc262_ultra_automute,
12695 },
Jiang zhe0e31daf2008-03-20 12:12:39 +010012696 [ALC262_LENOVO_3000] = {
12697 .mixers = { alc262_lenovo_3000_mixer },
12698 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
Daniel T Chene2595322009-12-19 18:19:02 -050012699 alc262_lenovo_3000_unsol_verbs,
12700 alc262_lenovo_3000_init_verbs },
Jiang zhe0e31daf2008-03-20 12:12:39 +010012701 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12702 .dac_nids = alc262_dac_nids,
12703 .hp_nid = 0x03,
12704 .dig_out_nid = ALC262_DIGOUT_NID,
12705 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12706 .channel_mode = alc262_modes,
12707 .input_mux = &alc262_fujitsu_capture_source,
12708 .unsol_event = alc262_lenovo_3000_unsol_event,
12709 },
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012710 [ALC262_NEC] = {
12711 .mixers = { alc262_nec_mixer },
12712 .init_verbs = { alc262_nec_verbs },
12713 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12714 .dac_nids = alc262_dac_nids,
12715 .hp_nid = 0x03,
12716 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12717 .channel_mode = alc262_modes,
12718 .input_mux = &alc262_capture_source,
12719 },
Kailang Yang4e555fe2008-08-26 13:05:55 +020012720 [ALC262_TOSHIBA_S06] = {
12721 .mixers = { alc262_toshiba_s06_mixer },
12722 .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
12723 alc262_eapd_verbs },
12724 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12725 .capsrc_nids = alc262_dmic_capsrc_nids,
12726 .dac_nids = alc262_dac_nids,
12727 .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
Takashi Iwaiae14ef62009-06-22 08:16:56 +020012728 .num_adc_nids = 1, /* single ADC */
Kailang Yang4e555fe2008-08-26 13:05:55 +020012729 .dig_out_nid = ALC262_DIGOUT_NID,
12730 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12731 .channel_mode = alc262_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012732 .unsol_event = alc_sku_unsol_event,
12733 .setup = alc262_toshiba_s06_setup,
12734 .init_hook = alc_inithook,
Kailang Yang4e555fe2008-08-26 13:05:55 +020012735 },
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012736 [ALC262_TOSHIBA_RX1] = {
12737 .mixers = { alc262_toshiba_rx1_mixer },
12738 .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
12739 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12740 .dac_nids = alc262_dac_nids,
12741 .hp_nid = 0x03,
12742 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12743 .channel_mode = alc262_modes,
12744 .input_mux = &alc262_capture_source,
12745 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012746 .setup = alc262_hippo_setup,
12747 .init_hook = alc262_hippo_automute,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012748 },
Tony Vroonba340e82009-02-02 19:01:30 +000012749 [ALC262_TYAN] = {
12750 .mixers = { alc262_tyan_mixer },
12751 .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
12752 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12753 .dac_nids = alc262_dac_nids,
12754 .hp_nid = 0x02,
12755 .dig_out_nid = ALC262_DIGOUT_NID,
12756 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12757 .channel_mode = alc262_modes,
12758 .input_mux = &alc262_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012759 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012760 .setup = alc262_tyan_setup,
12761 .init_hook = alc_automute_amp,
Tony Vroonba340e82009-02-02 19:01:30 +000012762 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012763};
12764
12765static int patch_alc262(struct hda_codec *codec)
12766{
12767 struct alc_spec *spec;
12768 int board_config;
12769 int err;
12770
Robert P. J. Daydc041e02006-12-19 14:44:15 +010012771 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010012772 if (spec == NULL)
12773 return -ENOMEM;
12774
12775 codec->spec = spec;
12776#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012777 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
12778 * under-run
12779 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012780 {
12781 int tmp;
12782 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
12783 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
12784 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
12785 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
12786 }
12787#endif
Kailang Yangda00c242010-03-19 11:23:45 +010012788 alc_auto_parse_customize_define(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012789
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020012790 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
12791
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012792 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
12793 alc262_models,
12794 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +010012795
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012796 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020012797 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
12798 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010012799 board_config = ALC262_AUTO;
12800 }
12801
Takashi Iwai18675e42010-09-08 15:55:44 +020012802 if (board_config == ALC262_AUTO)
12803 alc_pick_fixup(codec, alc262_fixup_tbl, alc262_fixups, 1);
12804
Kailang Yangdf694da2005-12-05 19:42:22 +010012805 if (board_config == ALC262_AUTO) {
12806 /* automatic parse from the BIOS config */
12807 err = alc262_parse_auto_config(codec);
12808 if (err < 0) {
12809 alc_free(codec);
12810 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012811 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012812 printk(KERN_INFO
12813 "hda_codec: Cannot set up configuration "
12814 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010012815 board_config = ALC262_BASIC;
12816 }
12817 }
12818
Takashi Iwaidc1eae22010-07-29 15:30:02 +020012819 if (!spec->no_analog && has_cdefine_beep(codec)) {
Takashi Iwai07eba612009-02-19 08:06:35 +010012820 err = snd_hda_attach_beep_device(codec, 0x1);
12821 if (err < 0) {
12822 alc_free(codec);
12823 return err;
12824 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090012825 }
12826
Kailang Yangdf694da2005-12-05 19:42:22 +010012827 if (board_config != ALC262_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020012828 setup_preset(codec, &alc262_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010012829
Kailang Yangdf694da2005-12-05 19:42:22 +010012830 spec->stream_analog_playback = &alc262_pcm_analog_playback;
12831 spec->stream_analog_capture = &alc262_pcm_analog_capture;
Kailang Yangea1fb292008-08-26 12:58:38 +020012832
Kailang Yangdf694da2005-12-05 19:42:22 +010012833 spec->stream_digital_playback = &alc262_pcm_digital_playback;
12834 spec->stream_digital_capture = &alc262_pcm_digital_capture;
12835
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012836 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwai8c927b42009-06-22 10:56:54 +020012837 int i;
12838 /* check whether the digital-mic has to be supported */
12839 for (i = 0; i < spec->input_mux->num_items; i++) {
12840 if (spec->input_mux->items[i].index >= 9)
12841 break;
12842 }
12843 if (i < spec->input_mux->num_items) {
12844 /* use only ADC0 */
12845 spec->adc_nids = alc262_dmic_adc_nids;
12846 spec->num_adc_nids = 1;
12847 spec->capsrc_nids = alc262_dmic_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +010012848 } else {
Takashi Iwai8c927b42009-06-22 10:56:54 +020012849 /* all analog inputs */
12850 /* check whether NID 0x07 is valid */
12851 unsigned int wcap = get_wcaps(codec, 0x07);
12852
12853 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020012854 wcap = get_wcaps_type(wcap);
Takashi Iwai8c927b42009-06-22 10:56:54 +020012855 if (wcap != AC_WID_AUD_IN) {
12856 spec->adc_nids = alc262_adc_nids_alt;
12857 spec->num_adc_nids =
12858 ARRAY_SIZE(alc262_adc_nids_alt);
12859 spec->capsrc_nids = alc262_capsrc_nids_alt;
12860 } else {
12861 spec->adc_nids = alc262_adc_nids;
12862 spec->num_adc_nids =
12863 ARRAY_SIZE(alc262_adc_nids);
12864 spec->capsrc_nids = alc262_capsrc_nids;
12865 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012866 }
12867 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012868 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020012869 set_capture_mixer(codec);
Takashi Iwaidc1eae22010-07-29 15:30:02 +020012870 if (!spec->no_analog && has_cdefine_beep(codec))
Takashi Iwai07eba612009-02-19 08:06:35 +010012871 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Kailang Yangdf694da2005-12-05 19:42:22 +010012872
Takashi Iwai18675e42010-09-08 15:55:44 +020012873 if (board_config == ALC262_AUTO)
12874 alc_pick_fixup(codec, alc262_fixup_tbl, alc262_fixups, 0);
12875
Takashi Iwai2134ea42008-01-10 16:53:55 +010012876 spec->vmaster_nid = 0x0c;
12877
Kailang Yangdf694da2005-12-05 19:42:22 +010012878 codec->patch_ops = alc_patch_ops;
12879 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012880 spec->init_hook = alc262_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020012881#ifdef CONFIG_SND_HDA_POWER_SAVE
12882 if (!spec->loopback.amplist)
12883 spec->loopback.amplist = alc262_loopbacks;
12884#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020012885
Kailang Yangdf694da2005-12-05 19:42:22 +010012886 return 0;
12887}
12888
Kailang Yangdf694da2005-12-05 19:42:22 +010012889/*
Kailang Yanga361d842007-06-05 12:30:55 +020012890 * ALC268 channel source setting (2 channel)
12891 */
12892#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
12893#define alc268_modes alc260_modes
Kailang Yangea1fb292008-08-26 12:58:38 +020012894
Kailang Yanga361d842007-06-05 12:30:55 +020012895static hda_nid_t alc268_dac_nids[2] = {
12896 /* front, hp */
12897 0x02, 0x03
12898};
12899
12900static hda_nid_t alc268_adc_nids[2] = {
12901 /* ADC0-1 */
12902 0x08, 0x07
12903};
12904
12905static hda_nid_t alc268_adc_nids_alt[1] = {
12906 /* ADC0 */
12907 0x08
12908};
12909
Takashi Iwaie1406342008-02-11 18:32:32 +010012910static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
12911
Kailang Yanga361d842007-06-05 12:30:55 +020012912static struct snd_kcontrol_new alc268_base_mixer[] = {
12913 /* output mixer control */
12914 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12915 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12916 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12917 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai33bf17a2007-08-21 11:51:42 +020012918 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12919 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12920 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +020012921 { }
12922};
12923
Takashi Iwai42171c12009-05-08 14:11:43 +020012924static struct snd_kcontrol_new alc268_toshiba_mixer[] = {
12925 /* output mixer control */
12926 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12927 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12928 ALC262_HIPPO_MASTER_SWITCH,
12929 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12930 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12931 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
12932 { }
12933};
12934
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012935/* bind Beep switches of both NID 0x0f and 0x10 */
12936static struct hda_bind_ctls alc268_bind_beep_sw = {
12937 .ops = &snd_hda_bind_sw,
12938 .values = {
12939 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
12940 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
12941 0
12942 },
12943};
12944
12945static struct snd_kcontrol_new alc268_beep_mixer[] = {
12946 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
12947 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
12948 { }
12949};
12950
Kailang Yangd1a991a2007-08-15 16:21:59 +020012951static struct hda_verb alc268_eapd_verbs[] = {
12952 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
12953 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
12954 { }
12955};
12956
Takashi Iwaid2738092007-08-16 14:59:45 +020012957/* Toshiba specific */
Takashi Iwaid2738092007-08-16 14:59:45 +020012958static struct hda_verb alc268_toshiba_verbs[] = {
12959 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12960 { } /* end */
12961};
12962
12963/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +020012964/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +020012965static struct hda_bind_ctls alc268_acer_bind_master_vol = {
12966 .ops = &snd_hda_bind_vol,
12967 .values = {
12968 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
12969 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
12970 0
12971 },
12972};
12973
Takashi Iwai889c4392007-08-23 18:56:52 +020012974/* mute/unmute internal speaker according to the hp jack and mute state */
12975static void alc268_acer_automute(struct hda_codec *codec, int force)
12976{
12977 struct alc_spec *spec = codec->spec;
12978 unsigned int mute;
12979
12980 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080012981 spec->jack_present = snd_hda_jack_detect(codec, 0x14);
Takashi Iwai889c4392007-08-23 18:56:52 +020012982 spec->sense_updated = 1;
12983 }
12984 if (spec->jack_present)
12985 mute = HDA_AMP_MUTE; /* mute internal speaker */
12986 else /* unmute internal speaker if necessary */
12987 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
12988 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
12989 HDA_AMP_MUTE, mute);
12990}
12991
12992
12993/* bind hp and internal speaker mute (with plug check) */
12994static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
12995 struct snd_ctl_elem_value *ucontrol)
12996{
12997 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
12998 long *valp = ucontrol->value.integer.value;
12999 int change;
13000
Takashi Iwai8de56b72009-07-24 16:51:47 +020013001 change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
Takashi Iwai889c4392007-08-23 18:56:52 +020013002 if (change)
13003 alc268_acer_automute(codec, 0);
13004 return change;
13005}
Takashi Iwaid2738092007-08-16 14:59:45 +020013006
Kailang Yang8ef355d2008-08-26 13:10:22 +020013007static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
13008 /* output mixer control */
13009 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13010 {
13011 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13012 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013013 .subdevice = HDA_SUBDEV_AMP_FLAG,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013014 .info = snd_hda_mixer_amp_switch_info,
13015 .get = snd_hda_mixer_amp_switch_get,
13016 .put = alc268_acer_master_sw_put,
13017 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13018 },
13019 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
13020 { }
13021};
13022
Takashi Iwaid2738092007-08-16 14:59:45 +020013023static struct snd_kcontrol_new alc268_acer_mixer[] = {
13024 /* output mixer control */
13025 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13026 {
13027 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13028 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013029 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwaid2738092007-08-16 14:59:45 +020013030 .info = snd_hda_mixer_amp_switch_info,
13031 .get = snd_hda_mixer_amp_switch_get,
13032 .put = alc268_acer_master_sw_put,
13033 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13034 },
Takashi Iwai33bf17a2007-08-21 11:51:42 +020013035 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13036 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
13037 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +020013038 { }
13039};
13040
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013041static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
13042 /* output mixer control */
13043 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13044 {
13045 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13046 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013047 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013048 .info = snd_hda_mixer_amp_switch_info,
13049 .get = snd_hda_mixer_amp_switch_get,
13050 .put = alc268_acer_master_sw_put,
13051 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13052 },
13053 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13054 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
13055 { }
13056};
13057
Kailang Yang8ef355d2008-08-26 13:10:22 +020013058static struct hda_verb alc268_acer_aspire_one_verbs[] = {
13059 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13060 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13061 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13062 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13063 {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
13064 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
13065 { }
13066};
13067
Takashi Iwaid2738092007-08-16 14:59:45 +020013068static struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013069 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
13070 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +020013071 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13072 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013073 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13074 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +020013075 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13076 { }
13077};
13078
13079/* unsolicited event for HP jack sensing */
Takashi Iwai42171c12009-05-08 14:11:43 +020013080#define alc268_toshiba_unsol_event alc262_hippo_unsol_event
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013081#define alc268_toshiba_setup alc262_hippo_setup
13082#define alc268_toshiba_automute alc262_hippo_automute
Takashi Iwaid2738092007-08-16 14:59:45 +020013083
13084static void alc268_acer_unsol_event(struct hda_codec *codec,
13085 unsigned int res)
13086{
Takashi Iwai889c4392007-08-23 18:56:52 +020013087 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020013088 return;
13089 alc268_acer_automute(codec, 1);
13090}
13091
Takashi Iwai889c4392007-08-23 18:56:52 +020013092static void alc268_acer_init_hook(struct hda_codec *codec)
13093{
13094 alc268_acer_automute(codec, 1);
13095}
13096
Kailang Yang8ef355d2008-08-26 13:10:22 +020013097/* toggle speaker-output according to the hp-jack state */
13098static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
13099{
13100 unsigned int present;
13101 unsigned char bits;
13102
Wu Fengguang864f92b2009-11-18 12:38:02 +080013103 present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013104 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang8ef355d2008-08-26 13:10:22 +020013105 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013106 HDA_AMP_MUTE, bits);
Kailang Yang8ef355d2008-08-26 13:10:22 +020013107 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013108 HDA_AMP_MUTE, bits);
Kailang Yang8ef355d2008-08-26 13:10:22 +020013109}
13110
Kailang Yang8ef355d2008-08-26 13:10:22 +020013111static void alc268_acer_lc_unsol_event(struct hda_codec *codec,
13112 unsigned int res)
13113{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013114 switch (res >> 26) {
13115 case ALC880_HP_EVENT:
Kailang Yang8ef355d2008-08-26 13:10:22 +020013116 alc268_aspire_one_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013117 break;
13118 case ALC880_MIC_EVENT:
13119 alc_mic_automute(codec);
13120 break;
13121 }
13122}
13123
13124static void alc268_acer_lc_setup(struct hda_codec *codec)
13125{
13126 struct alc_spec *spec = codec->spec;
13127 spec->ext_mic.pin = 0x18;
13128 spec->ext_mic.mux_idx = 0;
13129 spec->int_mic.pin = 0x12;
13130 spec->int_mic.mux_idx = 6;
13131 spec->auto_mic = 1;
Kailang Yang8ef355d2008-08-26 13:10:22 +020013132}
13133
13134static void alc268_acer_lc_init_hook(struct hda_codec *codec)
13135{
13136 alc268_aspire_one_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013137 alc_mic_automute(codec);
Kailang Yang8ef355d2008-08-26 13:10:22 +020013138}
13139
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013140static struct snd_kcontrol_new alc268_dell_mixer[] = {
13141 /* output mixer control */
13142 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13143 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13144 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13145 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
13146 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13147 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
13148 { }
13149};
13150
13151static struct hda_verb alc268_dell_verbs[] = {
13152 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13153 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13154 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013155 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013156 { }
13157};
13158
13159/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013160static void alc268_dell_setup(struct hda_codec *codec)
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013161{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013162 struct alc_spec *spec = codec->spec;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013163
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013164 spec->autocfg.hp_pins[0] = 0x15;
13165 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013166 spec->ext_mic.pin = 0x18;
13167 spec->ext_mic.mux_idx = 0;
13168 spec->int_mic.pin = 0x19;
13169 spec->int_mic.mux_idx = 1;
13170 spec->auto_mic = 1;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013171}
13172
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013173static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
13174 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
13175 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13176 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
13177 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
13178 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13179 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
13180 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
13181 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
13182 { }
13183};
13184
13185static struct hda_verb alc267_quanta_il1_verbs[] = {
13186 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13187 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
13188 { }
13189};
13190
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013191static void alc267_quanta_il1_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013192{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013193 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013194 spec->autocfg.hp_pins[0] = 0x15;
13195 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013196 spec->ext_mic.pin = 0x18;
13197 spec->ext_mic.mux_idx = 0;
13198 spec->int_mic.pin = 0x19;
13199 spec->int_mic.mux_idx = 1;
13200 spec->auto_mic = 1;
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013201}
13202
Kailang Yanga361d842007-06-05 12:30:55 +020013203/*
13204 * generic initialization of ADC, input mixers and output mixers
13205 */
13206static struct hda_verb alc268_base_init_verbs[] = {
13207 /* Unmute DAC0-1 and set vol = 0 */
13208 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020013209 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020013210
13211 /*
13212 * Set up output mixers (0x0c - 0x0e)
13213 */
13214 /* set vol=0 to output mixers */
13215 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020013216 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
13217
13218 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13219 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13220
13221 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
13222 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
13223 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
13224 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13225 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13226 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13227 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13228 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13229
13230 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13231 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13232 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13233 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013234 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013235
13236 /* set PCBEEP vol = 0, mute connections */
13237 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13238 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13239 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020013240
Jiang Zhea9b3aa82007-12-20 13:13:13 +010013241 /* Unmute Selector 23h,24h and set the default input to mic-in */
Kailang Yangea1fb292008-08-26 12:58:38 +020013242
Jiang Zhea9b3aa82007-12-20 13:13:13 +010013243 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
13244 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13245 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
13246 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013247
Kailang Yanga361d842007-06-05 12:30:55 +020013248 { }
13249};
13250
13251/*
13252 * generic initialization of ADC, input mixers and output mixers
13253 */
13254static struct hda_verb alc268_volume_init_verbs[] = {
13255 /* set output DAC */
Takashi Iwai4cfb91c2009-01-23 12:53:09 +010013256 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13257 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020013258
13259 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13260 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13261 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13262 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13263 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13264
Kailang Yanga361d842007-06-05 12:30:55 +020013265 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020013266 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13267 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13268
13269 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013270 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013271
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013272 /* set PCBEEP vol = 0, mute connections */
13273 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13274 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13275 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020013276
13277 { }
13278};
13279
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013280static struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = {
13281 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13282 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
13283 { } /* end */
13284};
13285
Kailang Yanga361d842007-06-05 12:30:55 +020013286static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
13287 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13288 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013289 _DEFINE_CAPSRC(1),
Kailang Yanga361d842007-06-05 12:30:55 +020013290 { } /* end */
13291};
13292
13293static struct snd_kcontrol_new alc268_capture_mixer[] = {
13294 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13295 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
13296 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
13297 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013298 _DEFINE_CAPSRC(2),
Kailang Yanga361d842007-06-05 12:30:55 +020013299 { } /* end */
13300};
13301
13302static struct hda_input_mux alc268_capture_source = {
13303 .num_items = 4,
13304 .items = {
13305 { "Mic", 0x0 },
13306 { "Front Mic", 0x1 },
13307 { "Line", 0x2 },
13308 { "CD", 0x3 },
13309 },
13310};
13311
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013312static struct hda_input_mux alc268_acer_capture_source = {
13313 .num_items = 3,
13314 .items = {
13315 { "Mic", 0x0 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013316 { "Internal Mic", 0x1 },
13317 { "Line", 0x2 },
13318 },
13319};
13320
13321static struct hda_input_mux alc268_acer_dmic_capture_source = {
13322 .num_items = 3,
13323 .items = {
13324 { "Mic", 0x0 },
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013325 { "Internal Mic", 0x6 },
13326 { "Line", 0x2 },
13327 },
13328};
13329
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013330#ifdef CONFIG_SND_DEBUG
13331static struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013332 /* Volume widgets */
13333 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13334 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13335 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
13336 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
13337 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
13338 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
13339 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
13340 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
13341 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
13342 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
13343 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
13344 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
13345 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010013346 /* The below appears problematic on some hardwares */
13347 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013348 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13349 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
13350 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
13351 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
13352
13353 /* Modes for retasking pin widgets */
13354 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
13355 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
13356 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
13357 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
13358
13359 /* Controls for GPIO pins, assuming they are configured as outputs */
13360 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
13361 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
13362 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
13363 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
13364
13365 /* Switches to allow the digital SPDIF output pin to be enabled.
13366 * The ALC268 does not have an SPDIF input.
13367 */
13368 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
13369
13370 /* A switch allowing EAPD to be enabled. Some laptops seem to use
13371 * this output to turn on an external amplifier.
13372 */
13373 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
13374 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
13375
13376 { } /* end */
13377};
13378#endif
13379
Kailang Yanga361d842007-06-05 12:30:55 +020013380/* create input playback/capture controls for the given pin */
13381static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
13382 const char *ctlname, int idx)
13383{
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013384 hda_nid_t dac;
Kailang Yanga361d842007-06-05 12:30:55 +020013385 int err;
13386
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013387 switch (nid) {
13388 case 0x14:
13389 case 0x16:
13390 dac = 0x02;
13391 break;
13392 case 0x15:
Takashi Iwaib08b1632010-07-30 14:08:25 +020013393 case 0x1a: /* ALC259/269 only */
13394 case 0x1b: /* ALC259/269 only */
Kailang Yang531d8792010-04-09 10:57:33 +020013395 case 0x21: /* ALC269vb has this pin, too */
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013396 dac = 0x03;
13397 break;
13398 default:
Takashi Iwaic7a94342010-07-30 14:10:43 +020013399 snd_printd(KERN_WARNING "hda_codec: "
13400 "ignoring pin 0x%x as unknown\n", nid);
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013401 return 0;
13402 }
13403 if (spec->multiout.dac_nids[0] != dac &&
13404 spec->multiout.dac_nids[1] != dac) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013405 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013406 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
Kailang Yanga361d842007-06-05 12:30:55 +020013407 HDA_OUTPUT));
13408 if (err < 0)
13409 return err;
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013410 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
13411 }
13412
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013413 if (nid != 0x16)
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013414 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Kailang Yanga361d842007-06-05 12:30:55 +020013415 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013416 else /* mono */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013417 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013418 HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013419 if (err < 0)
13420 return err;
13421 return 0;
13422}
13423
13424/* add playback controls from the parsed DAC table */
13425static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
13426 const struct auto_pin_cfg *cfg)
13427{
13428 hda_nid_t nid;
13429 int err;
13430
Kailang Yanga361d842007-06-05 12:30:55 +020013431 spec->multiout.dac_nids = spec->private_dac_nids;
Kailang Yanga361d842007-06-05 12:30:55 +020013432
13433 nid = cfg->line_out_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013434 if (nid) {
13435 const char *name;
13436 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
13437 name = "Speaker";
13438 else
13439 name = "Front";
13440 err = alc268_new_analog_output(spec, nid, name, 0);
13441 if (err < 0)
13442 return err;
13443 }
Kailang Yanga361d842007-06-05 12:30:55 +020013444
13445 nid = cfg->speaker_pins[0];
13446 if (nid == 0x1d) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013447 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Speaker",
Kailang Yanga361d842007-06-05 12:30:55 +020013448 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
13449 if (err < 0)
13450 return err;
David Henningsson7bfb9c02010-08-02 13:13:25 +020013451 } else if (nid) {
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013452 err = alc268_new_analog_output(spec, nid, "Speaker", 0);
13453 if (err < 0)
13454 return err;
Kailang Yanga361d842007-06-05 12:30:55 +020013455 }
13456 nid = cfg->hp_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013457 if (nid) {
13458 err = alc268_new_analog_output(spec, nid, "Headphone", 0);
13459 if (err < 0)
13460 return err;
13461 }
Kailang Yanga361d842007-06-05 12:30:55 +020013462
13463 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
13464 if (nid == 0x16) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013465 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, "Mono",
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013466 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013467 if (err < 0)
13468 return err;
13469 }
Kailang Yangea1fb292008-08-26 12:58:38 +020013470 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020013471}
13472
13473/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020013474static int alc268_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yanga361d842007-06-05 12:30:55 +020013475 const struct auto_pin_cfg *cfg)
13476{
Takashi Iwai05f5f472009-08-25 13:10:18 +020013477 return alc_auto_create_input_ctls(codec, cfg, 0, 0x23, 0x24);
Kailang Yanga361d842007-06-05 12:30:55 +020013478}
13479
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013480static void alc268_auto_set_output_and_unmute(struct hda_codec *codec,
13481 hda_nid_t nid, int pin_type)
13482{
13483 int idx;
13484
13485 alc_set_pin_output(codec, nid, pin_type);
13486 if (nid == 0x14 || nid == 0x16)
13487 idx = 0;
13488 else
13489 idx = 1;
13490 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
13491}
13492
13493static void alc268_auto_init_multi_out(struct hda_codec *codec)
13494{
13495 struct alc_spec *spec = codec->spec;
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013496 int i;
13497
13498 for (i = 0; i < spec->autocfg.line_outs; i++) {
13499 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013500 int pin_type = get_pin_type(spec->autocfg.line_out_type);
13501 alc268_auto_set_output_and_unmute(codec, nid, pin_type);
13502 }
13503}
13504
13505static void alc268_auto_init_hp_out(struct hda_codec *codec)
13506{
13507 struct alc_spec *spec = codec->spec;
13508 hda_nid_t pin;
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013509 int i;
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013510
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013511 for (i = 0; i < spec->autocfg.hp_outs; i++) {
13512 pin = spec->autocfg.hp_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013513 alc268_auto_set_output_and_unmute(codec, pin, PIN_HP);
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013514 }
13515 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
13516 pin = spec->autocfg.speaker_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013517 alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT);
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013518 }
13519 if (spec->autocfg.mono_out_pin)
13520 snd_hda_codec_write(codec, spec->autocfg.mono_out_pin, 0,
13521 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013522}
13523
Kailang Yanga361d842007-06-05 12:30:55 +020013524static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
13525{
13526 struct alc_spec *spec = codec->spec;
13527 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
13528 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
13529 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
13530 unsigned int dac_vol1, dac_vol2;
13531
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013532 if (line_nid == 0x1d || speaker_nid == 0x1d) {
Kailang Yanga361d842007-06-05 12:30:55 +020013533 snd_hda_codec_write(codec, speaker_nid, 0,
13534 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013535 /* mute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013536 snd_hda_codec_write(codec, 0x0f, 0,
13537 AC_VERB_SET_AMP_GAIN_MUTE,
13538 AMP_IN_UNMUTE(1));
13539 snd_hda_codec_write(codec, 0x10, 0,
13540 AC_VERB_SET_AMP_GAIN_MUTE,
13541 AMP_IN_UNMUTE(1));
13542 } else {
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013543 /* unmute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013544 snd_hda_codec_write(codec, 0x0f, 0,
13545 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13546 snd_hda_codec_write(codec, 0x10, 0,
13547 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13548 }
13549
13550 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020013551 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013552 dac_vol2 = AMP_OUT_ZERO;
13553 else if (line_nid == 0x15)
13554 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020013555 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013556 dac_vol2 = AMP_OUT_ZERO;
13557 else if (hp_nid == 0x15)
13558 dac_vol1 = AMP_OUT_ZERO;
13559 if (line_nid != 0x16 || hp_nid != 0x16 ||
13560 spec->autocfg.line_out_pins[1] != 0x16 ||
13561 spec->autocfg.line_out_pins[2] != 0x16)
13562 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
13563
13564 snd_hda_codec_write(codec, 0x02, 0,
13565 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
13566 snd_hda_codec_write(codec, 0x03, 0,
13567 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
13568}
13569
Sasha Alexandrdef319f2009-06-16 16:00:15 -040013570/* pcm configuration: identical with ALC880 */
Kailang Yanga361d842007-06-05 12:30:55 +020013571#define alc268_pcm_analog_playback alc880_pcm_analog_playback
13572#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010013573#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020013574#define alc268_pcm_digital_playback alc880_pcm_digital_playback
13575
13576/*
13577 * BIOS auto configuration
13578 */
13579static int alc268_parse_auto_config(struct hda_codec *codec)
13580{
13581 struct alc_spec *spec = codec->spec;
13582 int err;
13583 static hda_nid_t alc268_ignore[] = { 0 };
13584
13585 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13586 alc268_ignore);
13587 if (err < 0)
13588 return err;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013589 if (!spec->autocfg.line_outs) {
13590 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
13591 spec->multiout.max_channels = 2;
13592 spec->no_analog = 1;
13593 goto dig_only;
13594 }
Kailang Yanga361d842007-06-05 12:30:55 +020013595 return 0; /* can't find valid BIOS pin config */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013596 }
Kailang Yanga361d842007-06-05 12:30:55 +020013597 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
13598 if (err < 0)
13599 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020013600 err = alc268_auto_create_input_ctls(codec, &spec->autocfg);
Kailang Yanga361d842007-06-05 12:30:55 +020013601 if (err < 0)
13602 return err;
13603
13604 spec->multiout.max_channels = 2;
13605
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013606 dig_only:
Kailang Yanga361d842007-06-05 12:30:55 +020013607 /* digital only support output */
Takashi Iwai757899a2010-07-30 10:48:14 +020013608 alc_auto_parse_digital(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +020013609 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013610 add_mixer(spec, spec->kctls.list);
Kailang Yanga361d842007-06-05 12:30:55 +020013611
Takashi Iwai892981f2009-03-02 08:04:35 +010013612 if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013613 add_mixer(spec, alc268_beep_mixer);
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013614
Takashi Iwaid88897e2008-10-31 15:01:37 +010013615 add_verb(spec, alc268_volume_init_verbs);
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030013616 spec->num_mux_defs = 2;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020013617 spec->input_mux = &spec->private_imux[0];
Kailang Yanga361d842007-06-05 12:30:55 +020013618
Takashi Iwai776e1842007-08-29 15:07:11 +020013619 err = alc_auto_add_mic_boost(codec);
13620 if (err < 0)
13621 return err;
13622
Kailang Yang6227cdc2010-02-25 08:36:52 +010013623 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai1d955eb2009-06-29 11:33:53 +020013624
Kailang Yanga361d842007-06-05 12:30:55 +020013625 return 1;
13626}
13627
Kailang Yanga361d842007-06-05 12:30:55 +020013628#define alc268_auto_init_analog_input alc882_auto_init_analog_input
13629
13630/* init callback for auto-configuration model -- overriding the default init */
13631static void alc268_auto_init(struct hda_codec *codec)
13632{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013633 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020013634 alc268_auto_init_multi_out(codec);
13635 alc268_auto_init_hp_out(codec);
13636 alc268_auto_init_mono_speaker_out(codec);
13637 alc268_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020013638 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013639 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020013640 alc_inithook(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020013641}
13642
13643/*
13644 * configuration and preset
13645 */
13646static const char *alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013647 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020013648 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020013649 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020013650 [ALC268_ACER] = "acer",
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013651 [ALC268_ACER_DMIC] = "acer-dmic",
Kailang Yang8ef355d2008-08-26 13:10:22 +020013652 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013653 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013654 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013655#ifdef CONFIG_SND_DEBUG
13656 [ALC268_TEST] = "test",
13657#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013658 [ALC268_AUTO] = "auto",
13659};
13660
13661static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020013662 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013663 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010013664 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013665 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010013666 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020013667 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
13668 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013669 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Daniel T Chena1bf8082009-11-01 18:32:29 -050013670 SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0,
13671 "Dell Inspiron Mini9/Vostro A90", ALC268_DELL),
Takashi Iwai33d78672009-09-08 11:03:41 +020013672 /* almost compatible with toshiba but with optional digital outs;
13673 * auto-probing seems working fine
13674 */
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013675 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series",
Takashi Iwai33d78672009-09-08 11:03:41 +020013676 ALC268_AUTO),
Kailang Yanga361d842007-06-05 12:30:55 +020013677 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013678 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Tony Vroon378bd6a2008-06-04 12:08:30 +020013679 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020013680 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013681 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Kailang Yanga361d842007-06-05 12:30:55 +020013682 {}
13683};
13684
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013685/* Toshiba laptops have no unique PCI SSID but only codec SSID */
13686static struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
13687 SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO),
13688 SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO),
13689 SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
13690 ALC268_TOSHIBA),
13691 {}
13692};
13693
Kailang Yanga361d842007-06-05 12:30:55 +020013694static struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013695 [ALC267_QUANTA_IL1] = {
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013696 .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer,
13697 alc268_capture_nosrc_mixer },
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013698 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13699 alc267_quanta_il1_verbs },
13700 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13701 .dac_nids = alc268_dac_nids,
13702 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13703 .adc_nids = alc268_adc_nids_alt,
13704 .hp_nid = 0x03,
13705 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13706 .channel_mode = alc268_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013707 .unsol_event = alc_sku_unsol_event,
13708 .setup = alc267_quanta_il1_setup,
13709 .init_hook = alc_inithook,
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013710 },
Kailang Yanga361d842007-06-05 12:30:55 +020013711 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013712 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13713 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020013714 .init_verbs = { alc268_base_init_verbs },
13715 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13716 .dac_nids = alc268_dac_nids,
13717 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13718 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013719 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020013720 .hp_nid = 0x03,
13721 .dig_out_nid = ALC268_DIGOUT_NID,
13722 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13723 .channel_mode = alc268_modes,
13724 .input_mux = &alc268_capture_source,
13725 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013726 [ALC268_TOSHIBA] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020013727 .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013728 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013729 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13730 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013731 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13732 .dac_nids = alc268_dac_nids,
13733 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13734 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013735 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013736 .hp_nid = 0x03,
13737 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13738 .channel_mode = alc268_modes,
13739 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020013740 .unsol_event = alc268_toshiba_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013741 .setup = alc268_toshiba_setup,
13742 .init_hook = alc268_toshiba_automute,
Takashi Iwaid2738092007-08-16 14:59:45 +020013743 },
13744 [ALC268_ACER] = {
Takashi Iwai432fd132009-09-30 08:13:44 +020013745 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013746 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013747 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13748 alc268_acer_verbs },
13749 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13750 .dac_nids = alc268_dac_nids,
13751 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13752 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013753 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020013754 .hp_nid = 0x02,
13755 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13756 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013757 .input_mux = &alc268_acer_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020013758 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020013759 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013760 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013761 [ALC268_ACER_DMIC] = {
13762 .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
13763 alc268_beep_mixer },
13764 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13765 alc268_acer_verbs },
13766 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13767 .dac_nids = alc268_dac_nids,
13768 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13769 .adc_nids = alc268_adc_nids_alt,
13770 .capsrc_nids = alc268_capsrc_nids,
13771 .hp_nid = 0x02,
13772 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13773 .channel_mode = alc268_modes,
13774 .input_mux = &alc268_acer_dmic_capture_source,
13775 .unsol_event = alc268_acer_unsol_event,
13776 .init_hook = alc268_acer_init_hook,
13777 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013778 [ALC268_ACER_ASPIRE_ONE] = {
13779 .mixers = { alc268_acer_aspire_one_mixer,
Takashi Iwai22971e32009-02-10 11:56:44 +010013780 alc268_beep_mixer,
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013781 alc268_capture_nosrc_mixer },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013782 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13783 alc268_acer_aspire_one_verbs },
13784 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13785 .dac_nids = alc268_dac_nids,
13786 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13787 .adc_nids = alc268_adc_nids_alt,
13788 .capsrc_nids = alc268_capsrc_nids,
13789 .hp_nid = 0x03,
13790 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13791 .channel_mode = alc268_modes,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013792 .unsol_event = alc268_acer_lc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013793 .setup = alc268_acer_lc_setup,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013794 .init_hook = alc268_acer_lc_init_hook,
13795 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013796 [ALC268_DELL] = {
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013797 .mixers = { alc268_dell_mixer, alc268_beep_mixer,
13798 alc268_capture_nosrc_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013799 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13800 alc268_dell_verbs },
13801 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13802 .dac_nids = alc268_dac_nids,
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013803 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13804 .adc_nids = alc268_adc_nids_alt,
13805 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013806 .hp_nid = 0x02,
13807 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13808 .channel_mode = alc268_modes,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013809 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013810 .setup = alc268_dell_setup,
13811 .init_hook = alc_inithook,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013812 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013813 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013814 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13815 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013816 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13817 alc268_toshiba_verbs },
13818 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13819 .dac_nids = alc268_dac_nids,
13820 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13821 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013822 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013823 .hp_nid = 0x03,
13824 .dig_out_nid = ALC268_DIGOUT_NID,
13825 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13826 .channel_mode = alc268_modes,
13827 .input_mux = &alc268_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013828 .setup = alc268_toshiba_setup,
13829 .init_hook = alc268_toshiba_automute,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013830 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013831#ifdef CONFIG_SND_DEBUG
13832 [ALC268_TEST] = {
13833 .mixers = { alc268_test_mixer, alc268_capture_mixer },
13834 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13835 alc268_volume_init_verbs },
13836 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13837 .dac_nids = alc268_dac_nids,
13838 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13839 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013840 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013841 .hp_nid = 0x03,
13842 .dig_out_nid = ALC268_DIGOUT_NID,
13843 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13844 .channel_mode = alc268_modes,
13845 .input_mux = &alc268_capture_source,
13846 },
13847#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013848};
13849
13850static int patch_alc268(struct hda_codec *codec)
13851{
13852 struct alc_spec *spec;
13853 int board_config;
Takashi Iwai22971e32009-02-10 11:56:44 +010013854 int i, has_beep, err;
Kailang Yanga361d842007-06-05 12:30:55 +020013855
Julia Lawallef86f582009-12-19 08:18:03 +010013856 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yanga361d842007-06-05 12:30:55 +020013857 if (spec == NULL)
13858 return -ENOMEM;
13859
13860 codec->spec = spec;
13861
13862 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
13863 alc268_models,
13864 alc268_cfg_tbl);
13865
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013866 if (board_config < 0 || board_config >= ALC268_MODEL_LAST)
13867 board_config = snd_hda_check_board_codec_sid_config(codec,
Takashi Iwai50ae0aa2010-03-08 12:09:59 +010013868 ALC268_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl);
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013869
Kailang Yanga361d842007-06-05 12:30:55 +020013870 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020013871 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
13872 codec->chip_name);
Kailang Yanga361d842007-06-05 12:30:55 +020013873 board_config = ALC268_AUTO;
13874 }
13875
13876 if (board_config == ALC268_AUTO) {
13877 /* automatic parse from the BIOS config */
13878 err = alc268_parse_auto_config(codec);
13879 if (err < 0) {
13880 alc_free(codec);
13881 return err;
13882 } else if (!err) {
13883 printk(KERN_INFO
13884 "hda_codec: Cannot set up configuration "
13885 "from BIOS. Using base mode...\n");
13886 board_config = ALC268_3ST;
13887 }
13888 }
13889
13890 if (board_config != ALC268_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020013891 setup_preset(codec, &alc268_presets[board_config]);
Kailang Yanga361d842007-06-05 12:30:55 +020013892
Kailang Yanga361d842007-06-05 12:30:55 +020013893 spec->stream_analog_playback = &alc268_pcm_analog_playback;
13894 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010013895 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020013896
Kailang Yanga361d842007-06-05 12:30:55 +020013897 spec->stream_digital_playback = &alc268_pcm_digital_playback;
13898
Takashi Iwai22971e32009-02-10 11:56:44 +010013899 has_beep = 0;
13900 for (i = 0; i < spec->num_mixers; i++) {
13901 if (spec->mixers[i] == alc268_beep_mixer) {
13902 has_beep = 1;
13903 break;
13904 }
13905 }
13906
13907 if (has_beep) {
13908 err = snd_hda_attach_beep_device(codec, 0x1);
13909 if (err < 0) {
13910 alc_free(codec);
13911 return err;
13912 }
13913 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
13914 /* override the amp caps for beep generator */
13915 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013916 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
13917 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
13918 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
13919 (0 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwai22971e32009-02-10 11:56:44 +010013920 }
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013921
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013922 if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013923 /* check whether NID 0x07 is valid */
13924 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwai85860c02008-02-19 15:00:15 +010013925 int i;
Kailang Yanga361d842007-06-05 12:30:55 +020013926
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020013927 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013928 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020013929 wcap = get_wcaps_type(wcap);
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013930 if (spec->auto_mic ||
13931 wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013932 spec->adc_nids = alc268_adc_nids_alt;
13933 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020013934 if (spec->auto_mic)
13935 fixup_automic_adc(codec);
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013936 if (spec->auto_mic || spec->input_mux->num_items == 1)
13937 add_mixer(spec, alc268_capture_nosrc_mixer);
13938 else
13939 add_mixer(spec, alc268_capture_alt_mixer);
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013940 } else {
13941 spec->adc_nids = alc268_adc_nids;
13942 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
Takashi Iwaid88897e2008-10-31 15:01:37 +010013943 add_mixer(spec, alc268_capture_mixer);
Kailang Yanga361d842007-06-05 12:30:55 +020013944 }
Takashi Iwai85860c02008-02-19 15:00:15 +010013945 /* set default input source */
13946 for (i = 0; i < spec->num_adc_nids; i++)
13947 snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
13948 0, AC_VERB_SET_CONNECT_SEL,
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030013949 i < spec->num_mux_defs ?
13950 spec->input_mux[i].items[0].index :
Takashi Iwai85860c02008-02-19 15:00:15 +010013951 spec->input_mux->items[0].index);
Kailang Yanga361d842007-06-05 12:30:55 +020013952 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010013953
13954 spec->vmaster_nid = 0x02;
13955
Kailang Yanga361d842007-06-05 12:30:55 +020013956 codec->patch_ops = alc_patch_ops;
13957 if (board_config == ALC268_AUTO)
13958 spec->init_hook = alc268_auto_init;
Kailang Yangea1fb292008-08-26 12:58:38 +020013959
Kailang Yanga361d842007-06-05 12:30:55 +020013960 return 0;
13961}
13962
13963/*
Kailang Yangf6a92242007-12-13 16:52:54 +010013964 * ALC269 channel source setting (2 channel)
13965 */
13966#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
13967
13968#define alc269_dac_nids alc260_dac_nids
13969
13970static hda_nid_t alc269_adc_nids[1] = {
13971 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020013972 0x08,
13973};
13974
Takashi Iwaie01bf502008-08-21 16:25:07 +020013975static hda_nid_t alc269_capsrc_nids[1] = {
13976 0x23,
13977};
13978
Kailang Yang84898e82010-02-04 14:16:14 +010013979static hda_nid_t alc269vb_adc_nids[1] = {
13980 /* ADC1 */
13981 0x09,
13982};
13983
13984static hda_nid_t alc269vb_capsrc_nids[1] = {
13985 0x22,
13986};
13987
Takashi Iwai66946352010-03-29 17:21:45 +020013988static hda_nid_t alc269_adc_candidates[] = {
13989 0x08, 0x09, 0x07,
13990};
Takashi Iwaie01bf502008-08-21 16:25:07 +020013991
Kailang Yangf6a92242007-12-13 16:52:54 +010013992#define alc269_modes alc260_modes
13993#define alc269_capture_source alc880_lg_lw_capture_source
13994
13995static struct snd_kcontrol_new alc269_base_mixer[] = {
13996 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13997 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13998 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13999 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14000 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14001 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14002 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
14003 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
14004 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
14005 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
14006 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
14007 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
14008 { } /* end */
14009};
14010
Kailang Yang60db6b52008-08-26 13:13:00 +020014011static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
14012 /* output mixer control */
14013 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
14014 {
14015 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14016 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010014017 .subdevice = HDA_SUBDEV_AMP_FLAG,
Kailang Yang60db6b52008-08-26 13:13:00 +020014018 .info = snd_hda_mixer_amp_switch_info,
14019 .get = snd_hda_mixer_amp_switch_get,
14020 .put = alc268_acer_master_sw_put,
14021 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14022 },
14023 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14024 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14025 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
14026 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
14027 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
14028 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020014029 { }
14030};
14031
Tony Vroon64154832008-11-06 15:08:49 +000014032static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
14033 /* output mixer control */
14034 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
14035 {
14036 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14037 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010014038 .subdevice = HDA_SUBDEV_AMP_FLAG,
Tony Vroon64154832008-11-06 15:08:49 +000014039 .info = snd_hda_mixer_amp_switch_info,
14040 .get = snd_hda_mixer_amp_switch_get,
14041 .put = alc268_acer_master_sw_put,
14042 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14043 },
14044 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14045 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14046 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
14047 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
14048 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
14049 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
14050 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
14051 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
14052 HDA_CODEC_VOLUME("Dock Mic Boost", 0x1b, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000014053 { }
14054};
14055
Kailang Yang84898e82010-02-04 14:16:14 +010014056static struct snd_kcontrol_new alc269_laptop_mixer[] = {
Takashi Iwaiaa202452009-07-03 15:00:54 +020014057 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010014058 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwaiaa202452009-07-03 15:00:54 +020014059 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010014060 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yangf53281e2008-07-18 12:36:43 +020014061 { } /* end */
14062};
14063
Kailang Yang84898e82010-02-04 14:16:14 +010014064static struct snd_kcontrol_new alc269vb_laptop_mixer[] = {
14065 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14066 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14067 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
14068 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14069 { } /* end */
14070};
14071
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014072static struct snd_kcontrol_new alc269_asus_mixer[] = {
14073 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14074 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x0, HDA_INPUT),
14075 { } /* end */
14076};
14077
Kailang Yangf6a92242007-12-13 16:52:54 +010014078/* capture mixer elements */
Kailang Yang84898e82010-02-04 14:16:14 +010014079static struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
14080 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
14081 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
14082 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
14083 HDA_CODEC_VOLUME("IntMic Boost", 0x19, 0, HDA_INPUT),
14084 { } /* end */
14085};
14086
14087static struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = {
Kailang Yangf53281e2008-07-18 12:36:43 +020014088 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
14089 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Takashi Iwai26f5df22008-11-03 17:39:46 +010014090 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
14091 { } /* end */
14092};
14093
Kailang Yang84898e82010-02-04 14:16:14 +010014094static struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
14095 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
14096 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
14097 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
14098 HDA_CODEC_VOLUME("IntMic Boost", 0x19, 0, HDA_INPUT),
14099 { } /* end */
14100};
14101
14102static struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
14103 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
14104 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
14105 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
14106 { } /* end */
14107};
14108
Takashi Iwai26f5df22008-11-03 17:39:46 +010014109/* FSC amilo */
Kailang Yang84898e82010-02-04 14:16:14 +010014110#define alc269_fujitsu_mixer alc269_laptop_mixer
Kailang Yangf53281e2008-07-18 12:36:43 +020014111
Kailang Yang60db6b52008-08-26 13:13:00 +020014112static struct hda_verb alc269_quanta_fl1_verbs[] = {
14113 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14114 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14115 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14116 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
14117 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14118 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14119 { }
14120};
14121
Tony Vroon64154832008-11-06 15:08:49 +000014122static struct hda_verb alc269_lifebook_verbs[] = {
14123 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14124 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
14125 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14126 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14127 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
14128 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14129 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14130 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
14131 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14132 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14133 { }
14134};
14135
Kailang Yang60db6b52008-08-26 13:13:00 +020014136/* toggle speaker-output according to the hp-jack state */
14137static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
14138{
14139 unsigned int present;
14140 unsigned char bits;
14141
Wu Fengguang864f92b2009-11-18 12:38:02 +080014142 present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014143 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang60db6b52008-08-26 13:13:00 +020014144 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014145 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020014146 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014147 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020014148
14149 snd_hda_codec_write(codec, 0x20, 0,
14150 AC_VERB_SET_COEF_INDEX, 0x0c);
14151 snd_hda_codec_write(codec, 0x20, 0,
14152 AC_VERB_SET_PROC_COEF, 0x680);
14153
14154 snd_hda_codec_write(codec, 0x20, 0,
14155 AC_VERB_SET_COEF_INDEX, 0x0c);
14156 snd_hda_codec_write(codec, 0x20, 0,
14157 AC_VERB_SET_PROC_COEF, 0x480);
14158}
14159
Tony Vroon64154832008-11-06 15:08:49 +000014160/* toggle speaker-output according to the hp-jacks state */
14161static void alc269_lifebook_speaker_automute(struct hda_codec *codec)
14162{
14163 unsigned int present;
14164 unsigned char bits;
14165
14166 /* Check laptop headphone socket */
Wu Fengguang864f92b2009-11-18 12:38:02 +080014167 present = snd_hda_jack_detect(codec, 0x15);
Tony Vroon64154832008-11-06 15:08:49 +000014168
14169 /* Check port replicator headphone socket */
Wu Fengguang864f92b2009-11-18 12:38:02 +080014170 present |= snd_hda_jack_detect(codec, 0x1a);
Tony Vroon64154832008-11-06 15:08:49 +000014171
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014172 bits = present ? HDA_AMP_MUTE : 0;
Tony Vroon64154832008-11-06 15:08:49 +000014173 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014174 HDA_AMP_MUTE, bits);
Tony Vroon64154832008-11-06 15:08:49 +000014175 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014176 HDA_AMP_MUTE, bits);
Tony Vroon64154832008-11-06 15:08:49 +000014177
14178 snd_hda_codec_write(codec, 0x20, 0,
14179 AC_VERB_SET_COEF_INDEX, 0x0c);
14180 snd_hda_codec_write(codec, 0x20, 0,
14181 AC_VERB_SET_PROC_COEF, 0x680);
14182
14183 snd_hda_codec_write(codec, 0x20, 0,
14184 AC_VERB_SET_COEF_INDEX, 0x0c);
14185 snd_hda_codec_write(codec, 0x20, 0,
14186 AC_VERB_SET_PROC_COEF, 0x480);
14187}
14188
Tony Vroon64154832008-11-06 15:08:49 +000014189static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
14190{
14191 unsigned int present_laptop;
14192 unsigned int present_dock;
14193
Wu Fengguang864f92b2009-11-18 12:38:02 +080014194 present_laptop = snd_hda_jack_detect(codec, 0x18);
14195 present_dock = snd_hda_jack_detect(codec, 0x1b);
Tony Vroon64154832008-11-06 15:08:49 +000014196
14197 /* Laptop mic port overrides dock mic port, design decision */
14198 if (present_dock)
14199 snd_hda_codec_write(codec, 0x23, 0,
14200 AC_VERB_SET_CONNECT_SEL, 0x3);
14201 if (present_laptop)
14202 snd_hda_codec_write(codec, 0x23, 0,
14203 AC_VERB_SET_CONNECT_SEL, 0x0);
14204 if (!present_dock && !present_laptop)
14205 snd_hda_codec_write(codec, 0x23, 0,
14206 AC_VERB_SET_CONNECT_SEL, 0x1);
14207}
14208
Kailang Yang60db6b52008-08-26 13:13:00 +020014209static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
14210 unsigned int res)
14211{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014212 switch (res >> 26) {
14213 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020014214 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014215 break;
14216 case ALC880_MIC_EVENT:
14217 alc_mic_automute(codec);
14218 break;
14219 }
Kailang Yang60db6b52008-08-26 13:13:00 +020014220}
14221
Tony Vroon64154832008-11-06 15:08:49 +000014222static void alc269_lifebook_unsol_event(struct hda_codec *codec,
14223 unsigned int res)
14224{
14225 if ((res >> 26) == ALC880_HP_EVENT)
14226 alc269_lifebook_speaker_automute(codec);
14227 if ((res >> 26) == ALC880_MIC_EVENT)
14228 alc269_lifebook_mic_autoswitch(codec);
14229}
14230
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014231static void alc269_quanta_fl1_setup(struct hda_codec *codec)
14232{
14233 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010014234 spec->autocfg.hp_pins[0] = 0x15;
14235 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014236 spec->ext_mic.pin = 0x18;
14237 spec->ext_mic.mux_idx = 0;
14238 spec->int_mic.pin = 0x19;
14239 spec->int_mic.mux_idx = 1;
14240 spec->auto_mic = 1;
14241}
14242
Kailang Yang60db6b52008-08-26 13:13:00 +020014243static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
14244{
14245 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014246 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020014247}
14248
Tony Vroon64154832008-11-06 15:08:49 +000014249static void alc269_lifebook_init_hook(struct hda_codec *codec)
14250{
14251 alc269_lifebook_speaker_automute(codec);
14252 alc269_lifebook_mic_autoswitch(codec);
14253}
14254
Kailang Yang84898e82010-02-04 14:16:14 +010014255static struct hda_verb alc269_laptop_dmic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014256 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14257 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
14258 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14259 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14260 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
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 alc269_laptop_amic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014267 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14268 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
14269 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14270 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
14271 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14272 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14273 {}
14274};
14275
Kailang Yang84898e82010-02-04 14:16:14 +010014276static struct hda_verb alc269vb_laptop_dmic_init_verbs[] = {
14277 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
14278 {0x22, AC_VERB_SET_CONNECT_SEL, 0x06},
14279 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14280 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14281 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14282 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14283 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14284 {}
14285};
14286
14287static struct hda_verb alc269vb_laptop_amic_init_verbs[] = {
14288 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
14289 {0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
14290 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14291 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14292 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14293 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14294 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14295 {}
14296};
14297
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014298static struct hda_verb alc271_acer_dmic_verbs[] = {
14299 {0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
14300 {0x20, AC_VERB_SET_PROC_COEF, 0x4000},
14301 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14302 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14303 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14304 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14305 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00},
14306 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14307 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14308 {0x22, AC_VERB_SET_CONNECT_SEL, 6},
14309 { }
14310};
14311
Kailang Yang60db6b52008-08-26 13:13:00 +020014312/* toggle speaker-output according to the hp-jack state */
14313static void alc269_speaker_automute(struct hda_codec *codec)
14314{
Kailang Yangebb83ee2009-12-17 12:23:00 +010014315 struct alc_spec *spec = codec->spec;
14316 unsigned int nid = spec->autocfg.hp_pins[0];
Kailang Yang60db6b52008-08-26 13:13:00 +020014317 unsigned int present;
14318 unsigned char bits;
14319
Kailang Yangebb83ee2009-12-17 12:23:00 +010014320 present = snd_hda_jack_detect(codec, nid);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014321 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang60db6b52008-08-26 13:13:00 +020014322 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014323 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020014324 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014325 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020014326}
14327
Kailang Yang60db6b52008-08-26 13:13:00 +020014328/* unsolicited event for HP jack sensing */
Kailang Yang84898e82010-02-04 14:16:14 +010014329static void alc269_laptop_unsol_event(struct hda_codec *codec,
Kailang Yang60db6b52008-08-26 13:13:00 +020014330 unsigned int res)
14331{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014332 switch (res >> 26) {
14333 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020014334 alc269_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014335 break;
14336 case ALC880_MIC_EVENT:
14337 alc_mic_automute(codec);
14338 break;
14339 }
Kailang Yang60db6b52008-08-26 13:13:00 +020014340}
14341
Kailang Yang226b1ec2010-04-09 11:01:20 +020014342static void alc269_laptop_amic_setup(struct hda_codec *codec)
14343{
14344 struct alc_spec *spec = codec->spec;
14345 spec->autocfg.hp_pins[0] = 0x15;
14346 spec->autocfg.speaker_pins[0] = 0x14;
14347 spec->ext_mic.pin = 0x18;
14348 spec->ext_mic.mux_idx = 0;
14349 spec->int_mic.pin = 0x19;
14350 spec->int_mic.mux_idx = 1;
14351 spec->auto_mic = 1;
14352}
14353
Kailang Yang84898e82010-02-04 14:16:14 +010014354static void alc269_laptop_dmic_setup(struct hda_codec *codec)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014355{
14356 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010014357 spec->autocfg.hp_pins[0] = 0x15;
14358 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014359 spec->ext_mic.pin = 0x18;
14360 spec->ext_mic.mux_idx = 0;
14361 spec->int_mic.pin = 0x12;
14362 spec->int_mic.mux_idx = 5;
14363 spec->auto_mic = 1;
14364}
14365
Kailang Yang226b1ec2010-04-09 11:01:20 +020014366static void alc269vb_laptop_amic_setup(struct hda_codec *codec)
Kailang Yang84898e82010-02-04 14:16:14 +010014367{
14368 struct alc_spec *spec = codec->spec;
Kailang Yang226b1ec2010-04-09 11:01:20 +020014369 spec->autocfg.hp_pins[0] = 0x21;
Takashi Iwai20645d72010-03-02 11:14:01 +010014370 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014371 spec->ext_mic.pin = 0x18;
14372 spec->ext_mic.mux_idx = 0;
14373 spec->int_mic.pin = 0x19;
14374 spec->int_mic.mux_idx = 1;
14375 spec->auto_mic = 1;
14376}
14377
Kailang Yang226b1ec2010-04-09 11:01:20 +020014378static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
14379{
14380 struct alc_spec *spec = codec->spec;
14381 spec->autocfg.hp_pins[0] = 0x21;
14382 spec->autocfg.speaker_pins[0] = 0x14;
14383 spec->ext_mic.pin = 0x18;
14384 spec->ext_mic.mux_idx = 0;
14385 spec->int_mic.pin = 0x12;
14386 spec->int_mic.mux_idx = 6;
14387 spec->auto_mic = 1;
14388}
14389
Kailang Yang84898e82010-02-04 14:16:14 +010014390static void alc269_laptop_inithook(struct hda_codec *codec)
Kailang Yang60db6b52008-08-26 13:13:00 +020014391{
14392 alc269_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014393 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020014394}
14395
Kailang Yangf6a92242007-12-13 16:52:54 +010014396/*
14397 * generic initialization of ADC, input mixers and output mixers
14398 */
14399static struct hda_verb alc269_init_verbs[] = {
14400 /*
14401 * Unmute ADC0 and set the default input to mic-in
14402 */
Kailang Yang84898e82010-02-04 14:16:14 +010014403 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010014404
14405 /*
Kailang Yang84898e82010-02-04 14:16:14 +010014406 * Set up output mixers (0x02 - 0x03)
Kailang Yangf6a92242007-12-13 16:52:54 +010014407 */
14408 /* set vol=0 to output mixers */
14409 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14410 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14411
14412 /* set up input amps for analog loopback */
14413 /* Amp Indices: DAC = 0, mixer = 1 */
14414 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14415 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14416 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14417 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14418 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14419 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14420
14421 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14422 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14423 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14424 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14425 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14426 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14427 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14428
14429 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14430 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf6a92242007-12-13 16:52:54 +010014431
Kailang Yang84898e82010-02-04 14:16:14 +010014432 /* FIXME: use Mux-type input source selection */
Kailang Yangf6a92242007-12-13 16:52:54 +010014433 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14434 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang84898e82010-02-04 14:16:14 +010014435 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangf6a92242007-12-13 16:52:54 +010014436
14437 /* set EAPD */
14438 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yang84898e82010-02-04 14:16:14 +010014439 { }
14440};
14441
14442static struct hda_verb alc269vb_init_verbs[] = {
14443 /*
14444 * Unmute ADC0 and set the default input to mic-in
14445 */
14446 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14447
14448 /*
14449 * Set up output mixers (0x02 - 0x03)
14450 */
14451 /* set vol=0 to output mixers */
14452 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14453 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14454
14455 /* set up input amps for analog loopback */
14456 /* Amp Indices: DAC = 0, mixer = 1 */
14457 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14458 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14459 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14460 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14461 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14462 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14463
14464 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14465 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14466 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14467 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14468 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14469 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14470 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14471
14472 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14473 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14474
14475 /* FIXME: use Mux-type input source selection */
14476 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14477 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
14478 {0x22, AC_VERB_SET_CONNECT_SEL, 0x00},
14479
14480 /* set EAPD */
14481 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yangf6a92242007-12-13 16:52:54 +010014482 { }
14483};
14484
Takashi Iwai9d0b71b2009-08-24 14:10:30 +020014485#define alc269_auto_create_multi_out_ctls \
14486 alc268_auto_create_multi_out_ctls
Takashi Iwai05f5f472009-08-25 13:10:18 +020014487#define alc269_auto_create_input_ctls \
14488 alc268_auto_create_input_ctls
Kailang Yangf6a92242007-12-13 16:52:54 +010014489
14490#ifdef CONFIG_SND_HDA_POWER_SAVE
14491#define alc269_loopbacks alc880_loopbacks
14492#endif
14493
Sasha Alexandrdef319f2009-06-16 16:00:15 -040014494/* pcm configuration: identical with ALC880 */
Kailang Yangf6a92242007-12-13 16:52:54 +010014495#define alc269_pcm_analog_playback alc880_pcm_analog_playback
14496#define alc269_pcm_analog_capture alc880_pcm_analog_capture
14497#define alc269_pcm_digital_playback alc880_pcm_digital_playback
14498#define alc269_pcm_digital_capture alc880_pcm_digital_capture
14499
Takashi Iwaif03d3112009-03-05 14:18:16 +010014500static struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
14501 .substreams = 1,
14502 .channels_min = 2,
14503 .channels_max = 8,
14504 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14505 /* NID is set in alc_build_pcms */
14506 .ops = {
14507 .open = alc880_playback_pcm_open,
14508 .prepare = alc880_playback_pcm_prepare,
14509 .cleanup = alc880_playback_pcm_cleanup
14510 },
14511};
14512
14513static struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
14514 .substreams = 1,
14515 .channels_min = 2,
14516 .channels_max = 2,
14517 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14518 /* NID is set in alc_build_pcms */
14519};
14520
Takashi Iwaiad358792010-03-30 18:00:59 +020014521#ifdef CONFIG_SND_HDA_POWER_SAVE
14522static int alc269_mic2_for_mute_led(struct hda_codec *codec)
14523{
14524 switch (codec->subsystem_id) {
14525 case 0x103c1586:
14526 return 1;
14527 }
14528 return 0;
14529}
14530
14531static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
14532{
14533 /* update mute-LED according to the speaker mute state */
14534 if (nid == 0x01 || nid == 0x14) {
14535 int pinval;
14536 if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) &
14537 HDA_AMP_MUTE)
14538 pinval = 0x24;
14539 else
14540 pinval = 0x20;
14541 /* mic2 vref pin is used for mute LED control */
Takashi Iwaia68d5a52010-03-30 18:03:44 +020014542 snd_hda_codec_update_cache(codec, 0x19, 0,
14543 AC_VERB_SET_PIN_WIDGET_CONTROL,
14544 pinval);
Takashi Iwaiad358792010-03-30 18:00:59 +020014545 }
14546 return alc_check_power_status(codec, nid);
14547}
14548#endif /* CONFIG_SND_HDA_POWER_SAVE */
14549
Takashi Iwai840b64c2010-07-13 22:49:01 +020014550static int alc275_setup_dual_adc(struct hda_codec *codec)
14551{
14552 struct alc_spec *spec = codec->spec;
14553
14554 if (codec->vendor_id != 0x10ec0275 || !spec->auto_mic)
14555 return 0;
14556 if ((spec->ext_mic.pin >= 0x18 && spec->int_mic.pin <= 0x13) ||
14557 (spec->ext_mic.pin <= 0x12 && spec->int_mic.pin >= 0x18)) {
14558 if (spec->ext_mic.pin <= 0x12) {
14559 spec->private_adc_nids[0] = 0x08;
14560 spec->private_adc_nids[1] = 0x11;
14561 spec->private_capsrc_nids[0] = 0x23;
14562 spec->private_capsrc_nids[1] = 0x22;
14563 } else {
14564 spec->private_adc_nids[0] = 0x11;
14565 spec->private_adc_nids[1] = 0x08;
14566 spec->private_capsrc_nids[0] = 0x22;
14567 spec->private_capsrc_nids[1] = 0x23;
14568 }
14569 spec->adc_nids = spec->private_adc_nids;
14570 spec->capsrc_nids = spec->private_capsrc_nids;
14571 spec->num_adc_nids = 2;
14572 spec->dual_adc_switch = 1;
14573 snd_printdd("realtek: enabling dual ADC switchg (%02x:%02x)\n",
14574 spec->adc_nids[0], spec->adc_nids[1]);
14575 return 1;
14576 }
14577 return 0;
14578}
14579
Takashi Iwaid433a672010-09-20 15:11:54 +020014580/* different alc269-variants */
14581enum {
14582 ALC269_TYPE_NORMAL,
14583 ALC269_TYPE_ALC259,
14584 ALC269_TYPE_ALC271X,
14585};
14586
Kailang Yangf6a92242007-12-13 16:52:54 +010014587/*
14588 * BIOS auto configuration
14589 */
14590static int alc269_parse_auto_config(struct hda_codec *codec)
14591{
14592 struct alc_spec *spec = codec->spec;
Takashi Iwaicfb9fb52009-02-06 17:34:03 +010014593 int err;
Kailang Yangf6a92242007-12-13 16:52:54 +010014594 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
14595
14596 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
14597 alc269_ignore);
14598 if (err < 0)
14599 return err;
14600
14601 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
14602 if (err < 0)
14603 return err;
Takashi Iwaif3550d12010-09-20 15:09:03 +020014604 if (spec->codec_variant == ALC269_TYPE_NORMAL)
14605 err = alc269_auto_create_input_ctls(codec, &spec->autocfg);
14606 else
14607 err = alc_auto_create_input_ctls(codec, &spec->autocfg, 0,
14608 0x22, 0);
Kailang Yangf6a92242007-12-13 16:52:54 +010014609 if (err < 0)
14610 return err;
14611
14612 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
14613
Takashi Iwai757899a2010-07-30 10:48:14 +020014614 alc_auto_parse_digital(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014615
Takashi Iwai603c4012008-07-30 15:01:44 +020014616 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010014617 add_mixer(spec, spec->kctls.list);
Kailang Yangf6a92242007-12-13 16:52:54 +010014618
Takashi Iwaid433a672010-09-20 15:11:54 +020014619 if (spec->codec_variant != ALC269_TYPE_NORMAL) {
Kailang Yang84898e82010-02-04 14:16:14 +010014620 add_verb(spec, alc269vb_init_verbs);
Kailang Yang6227cdc2010-02-25 08:36:52 +010014621 alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21);
Kailang Yang84898e82010-02-04 14:16:14 +010014622 } else {
14623 add_verb(spec, alc269_init_verbs);
Kailang Yang6227cdc2010-02-25 08:36:52 +010014624 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Kailang Yang84898e82010-02-04 14:16:14 +010014625 }
14626
Kailang Yangf6a92242007-12-13 16:52:54 +010014627 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020014628 spec->input_mux = &spec->private_imux[0];
Takashi Iwai840b64c2010-07-13 22:49:01 +020014629
14630 if (!alc275_setup_dual_adc(codec))
14631 fillup_priv_adc_nids(codec, alc269_adc_candidates,
14632 sizeof(alc269_adc_candidates));
Takashi Iwai66946352010-03-29 17:21:45 +020014633
Takashi Iwaie01bf502008-08-21 16:25:07 +020014634 /* set default input source */
Takashi Iwai840b64c2010-07-13 22:49:01 +020014635 if (!spec->dual_adc_switch)
Takashi Iwai748cce42010-08-04 07:37:39 +020014636 select_or_unmute_capsrc(codec, spec->capsrc_nids[0],
14637 spec->input_mux->items[0].index);
Kailang Yangf6a92242007-12-13 16:52:54 +010014638
14639 err = alc_auto_add_mic_boost(codec);
14640 if (err < 0)
14641 return err;
14642
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010014643 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020014644 set_capture_mixer(codec);
Kailang Yangf53281e2008-07-18 12:36:43 +020014645
Kailang Yangf6a92242007-12-13 16:52:54 +010014646 return 1;
14647}
14648
Takashi Iwaie9af4f32009-08-29 23:23:08 +020014649#define alc269_auto_init_multi_out alc268_auto_init_multi_out
14650#define alc269_auto_init_hp_out alc268_auto_init_hp_out
Kailang Yangf6a92242007-12-13 16:52:54 +010014651#define alc269_auto_init_analog_input alc882_auto_init_analog_input
14652
14653
14654/* init callback for auto-configuration model -- overriding the default init */
14655static void alc269_auto_init(struct hda_codec *codec)
14656{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014657 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010014658 alc269_auto_init_multi_out(codec);
14659 alc269_auto_init_hp_out(codec);
14660 alc269_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020014661 alc_auto_init_digital(codec);
Kailang Yang9ad0e492010-09-14 23:22:00 +020014662 alc_init_jacks(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014663 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020014664 alc_inithook(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014665}
14666
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014667#ifdef SND_HDA_NEEDS_RESUME
14668static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
14669{
14670 int val = alc_read_coef_idx(codec, 0x04);
14671 if (power_up)
14672 val |= 1 << 11;
14673 else
14674 val &= ~(1 << 11);
14675 alc_write_coef_idx(codec, 0x04, val);
14676}
14677
Kailang Yang977ddd62010-09-15 10:02:29 +020014678#ifdef CONFIG_SND_HDA_POWER_SAVE
14679static int alc269_suspend(struct hda_codec *codec, pm_message_t state)
14680{
14681 struct alc_spec *spec = codec->spec;
Kailang Yang977ddd62010-09-15 10:02:29 +020014682
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014683 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017)
14684 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014685 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014686 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014687 msleep(150);
14688 }
14689
14690 alc_shutup(codec);
14691 if (spec && spec->power_hook)
14692 spec->power_hook(codec);
14693 return 0;
14694}
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014695#endif /* CONFIG_SND_HDA_POWER_SAVE */
14696
Kailang Yang977ddd62010-09-15 10:02:29 +020014697static int alc269_resume(struct hda_codec *codec)
14698{
Kailang Yang977ddd62010-09-15 10:02:29 +020014699 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014700 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014701 msleep(150);
14702 }
14703
14704 codec->patch_ops.init(codec);
14705
14706 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014707 alc269_toggle_power_output(codec, 1);
Kailang Yang977ddd62010-09-15 10:02:29 +020014708 msleep(200);
14709 }
14710
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014711 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018)
14712 alc269_toggle_power_output(codec, 1);
Kailang Yang977ddd62010-09-15 10:02:29 +020014713
14714 snd_hda_codec_resume_amp(codec);
14715 snd_hda_codec_resume_cache(codec);
Takashi Iwai9e5341b2010-09-21 09:57:06 +020014716 hda_call_check_power_status(codec, 0x01);
Kailang Yang977ddd62010-09-15 10:02:29 +020014717 return 0;
14718}
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014719#endif /* SND_HDA_NEEDS_RESUME */
Kailang Yang977ddd62010-09-15 10:02:29 +020014720
Takashi Iwaiff818c22010-04-12 08:59:25 +020014721enum {
14722 ALC269_FIXUP_SONY_VAIO,
David Henningsson145a9022010-09-16 10:07:53 +020014723 ALC269_FIXUP_DELL_M101Z,
Takashi Iwaiff818c22010-04-12 08:59:25 +020014724};
14725
Takashi Iwaiff818c22010-04-12 08:59:25 +020014726static const struct alc_fixup alc269_fixups[] = {
14727 [ALC269_FIXUP_SONY_VAIO] = {
Takashi Iwai73413b12010-08-30 09:39:57 +020014728 .verbs = (const struct hda_verb[]) {
14729 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
14730 {}
14731 }
Takashi Iwaiff818c22010-04-12 08:59:25 +020014732 },
David Henningsson145a9022010-09-16 10:07:53 +020014733 [ALC269_FIXUP_DELL_M101Z] = {
14734 .verbs = (const struct hda_verb[]) {
14735 /* Enables internal speaker */
14736 {0x20, AC_VERB_SET_COEF_INDEX, 13},
14737 {0x20, AC_VERB_SET_PROC_COEF, 0x4040},
14738 {}
14739 }
14740 },
Takashi Iwaiff818c22010-04-12 08:59:25 +020014741};
14742
14743static struct snd_pci_quirk alc269_fixup_tbl[] = {
Takashi Iwaiabdd8f52010-09-21 17:38:14 +020014744 SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
David Henningsson145a9022010-09-16 10:07:53 +020014745 SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
Takashi Iwaiff818c22010-04-12 08:59:25 +020014746 {}
14747};
14748
14749
Kailang Yangf6a92242007-12-13 16:52:54 +010014750/*
14751 * configuration and preset
14752 */
14753static const char *alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014754 [ALC269_BASIC] = "basic",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020014755 [ALC269_QUANTA_FL1] = "quanta",
Kailang Yang84898e82010-02-04 14:16:14 +010014756 [ALC269_AMIC] = "laptop-amic",
14757 [ALC269_DMIC] = "laptop-dmic",
Tony Vroon64154832008-11-06 15:08:49 +000014758 [ALC269_FUJITSU] = "fujitsu",
Takashi Iwai3d3792c2009-09-11 07:50:47 +020014759 [ALC269_LIFEBOOK] = "lifebook",
14760 [ALC269_AUTO] = "auto",
Kailang Yangf6a92242007-12-13 16:52:54 +010014761};
14762
14763static struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014764 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014765 SND_PCI_QUIRK(0x1025, 0x047c, "ACER ZGA", ALC271_ACER),
Kailang Yangf53281e2008-07-18 12:36:43 +020014766 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
Kailang Yang84898e82010-02-04 14:16:14 +010014767 ALC269_AMIC),
14768 SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC),
14769 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC),
14770 SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC),
14771 SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC),
14772 SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC),
14773 SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC),
14774 SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC),
14775 SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC),
14776 SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC),
14777 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82Jv", ALC269_AMIC),
14778 SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC),
14779 SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC),
14780 SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC),
14781 SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC),
14782 SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC),
14783 SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC),
14784 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC),
14785 SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC),
14786 SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC),
14787 SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC),
14788 SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC),
14789 SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC),
14790 SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC),
14791 SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC),
14792 SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC),
14793 SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC),
14794 SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC),
14795 SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC),
14796 SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC),
14797 SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC),
14798 SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC),
14799 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC),
14800 SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC),
14801 SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC),
14802 SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC),
14803 SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC),
Kailang Yangf53281e2008-07-18 12:36:43 +020014804 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
Kailang Yang84898e82010-02-04 14:16:14 +010014805 ALC269_DMIC),
Kailang Yang60db6b52008-08-26 13:13:00 +020014806 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
Kailang Yang84898e82010-02-04 14:16:14 +010014807 ALC269_DMIC),
14808 SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC),
14809 SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC),
Takashi Iwaiff818c22010-04-12 08:59:25 +020014810 SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_AUTO),
Tony Vroon64154832008-11-06 15:08:49 +000014811 SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
Kailang Yang61c2d2b2010-02-25 08:49:06 +010014812 SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC),
14813 SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
14814 SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_AMIC),
14815 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_AMIC),
14816 SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_DMIC),
14817 SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_DMIC),
Kailang Yangf6a92242007-12-13 16:52:54 +010014818 {}
14819};
14820
14821static struct alc_config_preset alc269_presets[] = {
14822 [ALC269_BASIC] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010014823 .mixers = { alc269_base_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010014824 .init_verbs = { alc269_init_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 },
Kailang Yang60db6b52008-08-26 13:13:00 +020014832 [ALC269_QUANTA_FL1] = {
14833 .mixers = { alc269_quanta_fl1_mixer },
14834 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
14835 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14836 .dac_nids = alc269_dac_nids,
14837 .hp_nid = 0x03,
14838 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14839 .channel_mode = alc269_modes,
14840 .input_mux = &alc269_capture_source,
14841 .unsol_event = alc269_quanta_fl1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014842 .setup = alc269_quanta_fl1_setup,
Kailang Yang60db6b52008-08-26 13:13:00 +020014843 .init_hook = alc269_quanta_fl1_init_hook,
14844 },
Kailang Yang84898e82010-02-04 14:16:14 +010014845 [ALC269_AMIC] = {
14846 .mixers = { alc269_laptop_mixer },
14847 .cap_mixer = alc269_laptop_analog_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020014848 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014849 alc269_laptop_amic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020014850 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14851 .dac_nids = alc269_dac_nids,
14852 .hp_nid = 0x03,
14853 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14854 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010014855 .unsol_event = alc269_laptop_unsol_event,
14856 .setup = alc269_laptop_amic_setup,
14857 .init_hook = alc269_laptop_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020014858 },
Kailang Yang84898e82010-02-04 14:16:14 +010014859 [ALC269_DMIC] = {
14860 .mixers = { alc269_laptop_mixer },
14861 .cap_mixer = alc269_laptop_digital_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020014862 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014863 alc269_laptop_dmic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020014864 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14865 .dac_nids = alc269_dac_nids,
14866 .hp_nid = 0x03,
14867 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14868 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010014869 .unsol_event = alc269_laptop_unsol_event,
14870 .setup = alc269_laptop_dmic_setup,
14871 .init_hook = alc269_laptop_inithook,
14872 },
14873 [ALC269VB_AMIC] = {
14874 .mixers = { alc269vb_laptop_mixer },
14875 .cap_mixer = alc269vb_laptop_analog_capture_mixer,
14876 .init_verbs = { alc269vb_init_verbs,
14877 alc269vb_laptop_amic_init_verbs },
14878 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14879 .dac_nids = alc269_dac_nids,
14880 .hp_nid = 0x03,
14881 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14882 .channel_mode = alc269_modes,
14883 .unsol_event = alc269_laptop_unsol_event,
Kailang Yang226b1ec2010-04-09 11:01:20 +020014884 .setup = alc269vb_laptop_amic_setup,
Kailang Yang84898e82010-02-04 14:16:14 +010014885 .init_hook = alc269_laptop_inithook,
14886 },
14887 [ALC269VB_DMIC] = {
14888 .mixers = { alc269vb_laptop_mixer },
14889 .cap_mixer = alc269vb_laptop_digital_capture_mixer,
14890 .init_verbs = { alc269vb_init_verbs,
14891 alc269vb_laptop_dmic_init_verbs },
14892 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14893 .dac_nids = alc269_dac_nids,
14894 .hp_nid = 0x03,
14895 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14896 .channel_mode = alc269_modes,
14897 .unsol_event = alc269_laptop_unsol_event,
14898 .setup = alc269vb_laptop_dmic_setup,
14899 .init_hook = alc269_laptop_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020014900 },
Takashi Iwai26f5df22008-11-03 17:39:46 +010014901 [ALC269_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010014902 .mixers = { alc269_fujitsu_mixer },
Kailang Yang84898e82010-02-04 14:16:14 +010014903 .cap_mixer = alc269_laptop_digital_capture_mixer,
Takashi Iwai26f5df22008-11-03 17:39:46 +010014904 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014905 alc269_laptop_dmic_init_verbs },
Takashi Iwai26f5df22008-11-03 17:39:46 +010014906 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14907 .dac_nids = alc269_dac_nids,
14908 .hp_nid = 0x03,
14909 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14910 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010014911 .unsol_event = alc269_laptop_unsol_event,
14912 .setup = alc269_laptop_dmic_setup,
14913 .init_hook = alc269_laptop_inithook,
Takashi Iwai26f5df22008-11-03 17:39:46 +010014914 },
Tony Vroon64154832008-11-06 15:08:49 +000014915 [ALC269_LIFEBOOK] = {
14916 .mixers = { alc269_lifebook_mixer },
14917 .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
14918 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14919 .dac_nids = alc269_dac_nids,
14920 .hp_nid = 0x03,
14921 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14922 .channel_mode = alc269_modes,
14923 .input_mux = &alc269_capture_source,
14924 .unsol_event = alc269_lifebook_unsol_event,
14925 .init_hook = alc269_lifebook_init_hook,
14926 },
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014927 [ALC271_ACER] = {
14928 .mixers = { alc269_asus_mixer },
14929 .cap_mixer = alc269vb_laptop_digital_capture_mixer,
14930 .init_verbs = { alc269_init_verbs, alc271_acer_dmic_verbs },
14931 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14932 .dac_nids = alc269_dac_nids,
14933 .adc_nids = alc262_dmic_adc_nids,
14934 .num_adc_nids = ARRAY_SIZE(alc262_dmic_adc_nids),
14935 .capsrc_nids = alc262_dmic_capsrc_nids,
14936 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14937 .channel_mode = alc269_modes,
14938 .input_mux = &alc269_capture_source,
14939 .dig_out_nid = ALC880_DIGOUT_NID,
14940 .unsol_event = alc_sku_unsol_event,
14941 .setup = alc269vb_laptop_dmic_setup,
14942 .init_hook = alc_inithook,
14943 },
Kailang Yangf6a92242007-12-13 16:52:54 +010014944};
14945
Kailang Yang977ddd62010-09-15 10:02:29 +020014946static int alc269_fill_coef(struct hda_codec *codec)
14947{
14948 int val;
14949
14950 if ((alc_read_coef_idx(codec, 0) & 0x00ff) < 0x015) {
14951 alc_write_coef_idx(codec, 0xf, 0x960b);
14952 alc_write_coef_idx(codec, 0xe, 0x8817);
14953 }
14954
14955 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x016) {
14956 alc_write_coef_idx(codec, 0xf, 0x960b);
14957 alc_write_coef_idx(codec, 0xe, 0x8814);
14958 }
14959
14960 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
14961 val = alc_read_coef_idx(codec, 0x04);
14962 /* Power up output pin */
14963 alc_write_coef_idx(codec, 0x04, val | (1<<11));
14964 }
14965
14966 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
14967 val = alc_read_coef_idx(codec, 0xd);
14968 if ((val & 0x0c00) >> 10 != 0x1) {
14969 /* Capless ramp up clock control */
14970 alc_write_coef_idx(codec, 0xd, val | 1<<10);
14971 }
14972 val = alc_read_coef_idx(codec, 0x17);
14973 if ((val & 0x01c0) >> 6 != 0x4) {
14974 /* Class D power on reset */
14975 alc_write_coef_idx(codec, 0x17, val | 1<<7);
14976 }
14977 }
14978 return 0;
14979}
14980
Kailang Yangf6a92242007-12-13 16:52:54 +010014981static int patch_alc269(struct hda_codec *codec)
14982{
14983 struct alc_spec *spec;
14984 int board_config;
14985 int err;
14986
14987 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
14988 if (spec == NULL)
14989 return -ENOMEM;
14990
14991 codec->spec = spec;
14992
Kailang Yangda00c242010-03-19 11:23:45 +010014993 alc_auto_parse_customize_define(codec);
14994
Kailang Yang274693f2009-12-03 10:07:50 +010014995 if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){
Kailang Yangc027ddc2010-03-19 11:33:06 +010014996 if (codec->bus->pci->subsystem_vendor == 0x1025 &&
Takashi Iwaid433a672010-09-20 15:11:54 +020014997 spec->cdefine.platform_type == 1) {
Kailang Yangc027ddc2010-03-19 11:33:06 +010014998 alc_codec_rename(codec, "ALC271X");
Takashi Iwaid433a672010-09-20 15:11:54 +020014999 spec->codec_variant = ALC269_TYPE_ALC271X;
15000 } else {
Kailang Yangc027ddc2010-03-19 11:33:06 +010015001 alc_codec_rename(codec, "ALC259");
Takashi Iwaid433a672010-09-20 15:11:54 +020015002 spec->codec_variant = ALC269_TYPE_ALC259;
15003 }
Kailang Yangc027ddc2010-03-19 11:33:06 +010015004 } else
15005 alc_fix_pll_init(codec, 0x20, 0x04, 15);
Kailang Yang274693f2009-12-03 10:07:50 +010015006
Kailang Yang977ddd62010-09-15 10:02:29 +020015007 alc269_fill_coef(codec);
15008
Kailang Yangf6a92242007-12-13 16:52:54 +010015009 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
15010 alc269_models,
15011 alc269_cfg_tbl);
15012
15013 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020015014 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
15015 codec->chip_name);
Kailang Yangf6a92242007-12-13 16:52:54 +010015016 board_config = ALC269_AUTO;
15017 }
15018
Takashi Iwaiff818c22010-04-12 08:59:25 +020015019 if (board_config == ALC269_AUTO)
15020 alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 1);
15021
Kailang Yangf6a92242007-12-13 16:52:54 +010015022 if (board_config == ALC269_AUTO) {
15023 /* automatic parse from the BIOS config */
15024 err = alc269_parse_auto_config(codec);
15025 if (err < 0) {
15026 alc_free(codec);
15027 return err;
15028 } else if (!err) {
15029 printk(KERN_INFO
15030 "hda_codec: Cannot set up configuration "
15031 "from BIOS. Using base mode...\n");
15032 board_config = ALC269_BASIC;
15033 }
15034 }
15035
Takashi Iwaidc1eae22010-07-29 15:30:02 +020015036 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020015037 err = snd_hda_attach_beep_device(codec, 0x1);
15038 if (err < 0) {
15039 alc_free(codec);
15040 return err;
15041 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090015042 }
15043
Kailang Yangf6a92242007-12-13 16:52:54 +010015044 if (board_config != ALC269_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020015045 setup_preset(codec, &alc269_presets[board_config]);
Kailang Yangf6a92242007-12-13 16:52:54 +010015046
Kailang Yang84898e82010-02-04 14:16:14 +010015047 if (board_config == ALC269_QUANTA_FL1) {
Takashi Iwaif03d3112009-03-05 14:18:16 +010015048 /* Due to a hardware problem on Lenovo Ideadpad, we need to
15049 * fix the sample rate of analog I/O to 44.1kHz
15050 */
15051 spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
15052 spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
Takashi Iwai840b64c2010-07-13 22:49:01 +020015053 } else if (spec->dual_adc_switch) {
15054 spec->stream_analog_playback = &alc269_pcm_analog_playback;
15055 /* switch ADC dynamically */
15056 spec->stream_analog_capture = &dualmic_pcm_analog_capture;
Takashi Iwaif03d3112009-03-05 14:18:16 +010015057 } else {
15058 spec->stream_analog_playback = &alc269_pcm_analog_playback;
15059 spec->stream_analog_capture = &alc269_pcm_analog_capture;
15060 }
Kailang Yangf6a92242007-12-13 16:52:54 +010015061 spec->stream_digital_playback = &alc269_pcm_digital_playback;
15062 spec->stream_digital_capture = &alc269_pcm_digital_capture;
15063
Takashi Iwai66946352010-03-29 17:21:45 +020015064 if (!spec->adc_nids) { /* wasn't filled automatically? use default */
Takashi Iwaid433a672010-09-20 15:11:54 +020015065 if (spec->codec_variant != ALC269_TYPE_NORMAL) {
Takashi Iwai66946352010-03-29 17:21:45 +020015066 spec->adc_nids = alc269_adc_nids;
15067 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
15068 spec->capsrc_nids = alc269_capsrc_nids;
15069 } else {
15070 spec->adc_nids = alc269vb_adc_nids;
15071 spec->num_adc_nids = ARRAY_SIZE(alc269vb_adc_nids);
15072 spec->capsrc_nids = alc269vb_capsrc_nids;
15073 }
Kailang Yang84898e82010-02-04 14:16:14 +010015074 }
15075
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015076 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020015077 set_capture_mixer(codec);
Takashi Iwaidc1eae22010-07-29 15:30:02 +020015078 if (has_cdefine_beep(codec))
Kailang Yangda00c242010-03-19 11:23:45 +010015079 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Kailang Yangf6a92242007-12-13 16:52:54 +010015080
Takashi Iwaiff818c22010-04-12 08:59:25 +020015081 if (board_config == ALC269_AUTO)
15082 alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 0);
15083
Takashi Iwai100d5eb2009-08-10 11:55:51 +020015084 spec->vmaster_nid = 0x02;
15085
Kailang Yangf6a92242007-12-13 16:52:54 +010015086 codec->patch_ops = alc_patch_ops;
Kailang Yang977ddd62010-09-15 10:02:29 +020015087#ifdef CONFIG_SND_HDA_POWER_SAVE
15088 codec->patch_ops.suspend = alc269_suspend;
15089#endif
15090#ifdef SND_HDA_NEEDS_RESUME
15091 codec->patch_ops.resume = alc269_resume;
15092#endif
Kailang Yangf6a92242007-12-13 16:52:54 +010015093 if (board_config == ALC269_AUTO)
15094 spec->init_hook = alc269_auto_init;
15095#ifdef CONFIG_SND_HDA_POWER_SAVE
15096 if (!spec->loopback.amplist)
15097 spec->loopback.amplist = alc269_loopbacks;
Takashi Iwaiad358792010-03-30 18:00:59 +020015098 if (alc269_mic2_for_mute_led(codec))
15099 codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps;
Kailang Yangf6a92242007-12-13 16:52:54 +010015100#endif
15101
15102 return 0;
15103}
15104
15105/*
Kailang Yangdf694da2005-12-05 19:42:22 +010015106 * ALC861 channel source setting (2/6 channel selection for 3-stack)
15107 */
15108
15109/*
15110 * set the path ways for 2 channel output
15111 * need to set the codec line out and mic 1 pin widgets to inputs
15112 */
15113static struct hda_verb alc861_threestack_ch2_init[] = {
15114 /* set pin widget 1Ah (line in) for input */
15115 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015116 /* set pin widget 18h (mic1/2) for input, for mic also enable
15117 * the vref
15118 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015119 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15120
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015121 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
15122#if 0
15123 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
15124 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
15125#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010015126 { } /* end */
15127};
15128/*
15129 * 6ch mode
15130 * need to set the codec line out and mic 1 pin widgets to outputs
15131 */
15132static struct hda_verb alc861_threestack_ch6_init[] = {
15133 /* set pin widget 1Ah (line in) for output (Back Surround)*/
15134 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15135 /* set pin widget 18h (mic1) for output (CLFE)*/
15136 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15137
15138 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015139 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015140
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015141 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
15142#if 0
15143 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
15144 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
15145#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010015146 { } /* end */
15147};
15148
15149static struct hda_channel_mode alc861_threestack_modes[2] = {
15150 { 2, alc861_threestack_ch2_init },
15151 { 6, alc861_threestack_ch6_init },
15152};
Takashi Iwai22309c32006-08-09 16:57:28 +020015153/* Set mic1 as input and unmute the mixer */
15154static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
15155 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15156 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
15157 { } /* end */
15158};
15159/* Set mic1 as output and mute mixer */
15160static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
15161 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15162 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
15163 { } /* end */
15164};
15165
15166static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
15167 { 2, alc861_uniwill_m31_ch2_init },
15168 { 4, alc861_uniwill_m31_ch4_init },
15169};
Kailang Yangdf694da2005-12-05 19:42:22 +010015170
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015171/* Set mic1 and line-in as input and unmute the mixer */
15172static struct hda_verb alc861_asus_ch2_init[] = {
15173 /* set pin widget 1Ah (line in) for input */
15174 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015175 /* set pin widget 18h (mic1/2) for input, for mic also enable
15176 * the vref
15177 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015178 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15179
15180 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
15181#if 0
15182 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
15183 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
15184#endif
15185 { } /* end */
15186};
15187/* Set mic1 nad line-in as output and mute mixer */
15188static struct hda_verb alc861_asus_ch6_init[] = {
15189 /* set pin widget 1Ah (line in) for output (Back Surround)*/
15190 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15191 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
15192 /* set pin widget 18h (mic1) for output (CLFE)*/
15193 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15194 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
15195 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
15196 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
15197
15198 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
15199#if 0
15200 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
15201 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
15202#endif
15203 { } /* end */
15204};
15205
15206static struct hda_channel_mode alc861_asus_modes[2] = {
15207 { 2, alc861_asus_ch2_init },
15208 { 6, alc861_asus_ch6_init },
15209};
15210
Kailang Yangdf694da2005-12-05 19:42:22 +010015211/* patch-ALC861 */
15212
15213static struct snd_kcontrol_new alc861_base_mixer[] = {
15214 /* output mixer control */
15215 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15216 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15217 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15218 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15219 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
15220
15221 /*Input mixer control */
15222 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15223 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
15224 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15225 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15226 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15227 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15228 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15229 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15230 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
15231 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015232
Kailang Yangdf694da2005-12-05 19:42:22 +010015233 { } /* end */
15234};
15235
15236static struct snd_kcontrol_new alc861_3ST_mixer[] = {
15237 /* output mixer control */
15238 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15239 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15240 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15241 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15242 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
15243
15244 /* Input mixer control */
15245 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15246 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
15247 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15248 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15249 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15250 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15251 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15252 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15253 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
15254 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015255
Kailang Yangdf694da2005-12-05 19:42:22 +010015256 {
15257 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15258 .name = "Channel Mode",
15259 .info = alc_ch_mode_info,
15260 .get = alc_ch_mode_get,
15261 .put = alc_ch_mode_put,
15262 .private_value = ARRAY_SIZE(alc861_threestack_modes),
15263 },
15264 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015265};
15266
Takashi Iwaid1d985f2006-11-23 19:27:12 +010015267static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015268 /* output mixer control */
15269 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15270 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15271 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020015272
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015273 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015274};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015275
Takashi Iwai22309c32006-08-09 16:57:28 +020015276static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
15277 /* output mixer control */
15278 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15279 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15280 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15281 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15282 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
15283
15284 /* Input mixer control */
15285 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15286 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
15287 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15288 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15289 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15290 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15291 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15292 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15293 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
15294 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015295
Takashi Iwai22309c32006-08-09 16:57:28 +020015296 {
15297 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15298 .name = "Channel Mode",
15299 .info = alc_ch_mode_info,
15300 .get = alc_ch_mode_get,
15301 .put = alc_ch_mode_put,
15302 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
15303 },
15304 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015305};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015306
15307static struct snd_kcontrol_new alc861_asus_mixer[] = {
15308 /* output mixer control */
15309 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15310 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15311 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15312 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15313 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
15314
15315 /* Input mixer control */
15316 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15317 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
15318 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15319 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15320 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15321 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15322 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15323 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15324 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015325 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
15326
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015327 {
15328 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15329 .name = "Channel Mode",
15330 .info = alc_ch_mode_info,
15331 .get = alc_ch_mode_get,
15332 .put = alc_ch_mode_put,
15333 .private_value = ARRAY_SIZE(alc861_asus_modes),
15334 },
15335 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015336};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015337
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015338/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010015339static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015340 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15341 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015342 { }
15343};
15344
Kailang Yangdf694da2005-12-05 19:42:22 +010015345/*
15346 * generic initialization of ADC, input mixers and output mixers
15347 */
15348static struct hda_verb alc861_base_init_verbs[] = {
15349 /*
15350 * Unmute ADC0 and set the default input to mic-in
15351 */
15352 /* port-A for surround (rear panel) */
15353 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15354 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
15355 /* port-B for mic-in (rear panel) with vref */
15356 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15357 /* port-C for line-in (rear panel) */
15358 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15359 /* port-D for Front */
15360 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15361 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15362 /* port-E for HP out (front panel) */
15363 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
15364 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015365 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015366 /* port-F for mic-in (front panel) with vref */
15367 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15368 /* port-G for CLFE (rear panel) */
15369 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15370 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
15371 /* port-H for side (rear panel) */
15372 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15373 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
15374 /* CD-in */
15375 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15376 /* route front mic to ADC1*/
15377 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15378 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015379
Kailang Yangdf694da2005-12-05 19:42:22 +010015380 /* Unmute DAC0~3 & spdif out*/
15381 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15382 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15383 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15384 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15385 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015386
Kailang Yangdf694da2005-12-05 19:42:22 +010015387 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15388 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15389 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15390 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15391 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015392
Kailang Yangdf694da2005-12-05 19:42:22 +010015393 /* Unmute Stereo Mixer 15 */
15394 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15395 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15396 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015397 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015398
15399 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15400 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15401 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15402 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15403 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15404 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15405 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15406 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015407 /* hp used DAC 3 (Front) */
15408 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015409 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15410
15411 { }
15412};
15413
15414static struct hda_verb alc861_threestack_init_verbs[] = {
15415 /*
15416 * Unmute ADC0 and set the default input to mic-in
15417 */
15418 /* port-A for surround (rear panel) */
15419 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15420 /* port-B for mic-in (rear panel) with vref */
15421 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15422 /* port-C for line-in (rear panel) */
15423 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15424 /* port-D for Front */
15425 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15426 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15427 /* port-E for HP out (front panel) */
15428 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
15429 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015430 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015431 /* port-F for mic-in (front panel) with vref */
15432 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15433 /* port-G for CLFE (rear panel) */
15434 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15435 /* port-H for side (rear panel) */
15436 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15437 /* CD-in */
15438 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15439 /* route front mic to ADC1*/
15440 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15441 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15442 /* Unmute DAC0~3 & spdif out*/
15443 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15444 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15445 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15446 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15447 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015448
Kailang Yangdf694da2005-12-05 19:42:22 +010015449 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15450 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15451 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15452 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15453 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015454
Kailang Yangdf694da2005-12-05 19:42:22 +010015455 /* Unmute Stereo Mixer 15 */
15456 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15457 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15458 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015459 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015460
15461 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15462 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15463 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15464 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15465 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15466 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15467 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15468 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015469 /* hp used DAC 3 (Front) */
15470 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015471 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15472 { }
15473};
Takashi Iwai22309c32006-08-09 16:57:28 +020015474
15475static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
15476 /*
15477 * Unmute ADC0 and set the default input to mic-in
15478 */
15479 /* port-A for surround (rear panel) */
15480 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15481 /* port-B for mic-in (rear panel) with vref */
15482 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15483 /* port-C for line-in (rear panel) */
15484 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15485 /* port-D for Front */
15486 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15487 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15488 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015489 /* this has to be set to VREF80 */
15490 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015491 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015492 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015493 /* port-F for mic-in (front panel) with vref */
15494 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15495 /* port-G for CLFE (rear panel) */
15496 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15497 /* port-H for side (rear panel) */
15498 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15499 /* CD-in */
15500 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15501 /* route front mic to ADC1*/
15502 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15503 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15504 /* Unmute DAC0~3 & spdif out*/
15505 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15506 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15507 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15508 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15509 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015510
Takashi Iwai22309c32006-08-09 16:57:28 +020015511 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15512 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15513 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15514 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15515 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015516
Takashi Iwai22309c32006-08-09 16:57:28 +020015517 /* Unmute Stereo Mixer 15 */
15518 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15519 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15520 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015521 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020015522
15523 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15524 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15525 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15526 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15527 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15528 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15529 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15530 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015531 /* hp used DAC 3 (Front) */
15532 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020015533 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15534 { }
15535};
15536
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015537static struct hda_verb alc861_asus_init_verbs[] = {
15538 /*
15539 * Unmute ADC0 and set the default input to mic-in
15540 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015541 /* port-A for surround (rear panel)
15542 * according to codec#0 this is the HP jack
15543 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015544 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
15545 /* route front PCM to HP */
15546 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
15547 /* port-B for mic-in (rear panel) with vref */
15548 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15549 /* port-C for line-in (rear panel) */
15550 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15551 /* port-D for Front */
15552 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15553 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15554 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015555 /* this has to be set to VREF80 */
15556 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015557 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015558 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015559 /* port-F for mic-in (front panel) with vref */
15560 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15561 /* port-G for CLFE (rear panel) */
15562 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15563 /* port-H for side (rear panel) */
15564 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15565 /* CD-in */
15566 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15567 /* route front mic to ADC1*/
15568 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15569 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15570 /* Unmute DAC0~3 & spdif out*/
15571 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15572 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15573 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15574 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15575 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15576 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15577 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15578 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15579 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15580 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015581
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015582 /* Unmute Stereo Mixer 15 */
15583 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15584 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15585 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015586 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015587
15588 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15589 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15590 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15591 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15592 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15593 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15594 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15595 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015596 /* hp used DAC 3 (Front) */
15597 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015598 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15599 { }
15600};
15601
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015602/* additional init verbs for ASUS laptops */
15603static struct hda_verb alc861_asus_laptop_init_verbs[] = {
15604 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
15605 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
15606 { }
15607};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015608
Kailang Yangdf694da2005-12-05 19:42:22 +010015609/*
15610 * generic initialization of ADC, input mixers and output mixers
15611 */
15612static struct hda_verb alc861_auto_init_verbs[] = {
15613 /*
15614 * Unmute ADC0 and set the default input to mic-in
15615 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015616 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010015617 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015618
Kailang Yangdf694da2005-12-05 19:42:22 +010015619 /* Unmute DAC0~3 & spdif out*/
15620 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15621 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15622 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15623 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15624 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015625
Kailang Yangdf694da2005-12-05 19:42:22 +010015626 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15627 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15628 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15629 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15630 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015631
Kailang Yangdf694da2005-12-05 19:42:22 +010015632 /* Unmute Stereo Mixer 15 */
15633 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15634 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15635 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15636 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
15637
Takashi Iwai1c209302009-07-22 15:17:45 +020015638 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15639 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15640 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15641 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15642 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15643 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15644 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15645 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015646
15647 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15648 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020015649 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15650 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015651 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15652 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020015653 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15654 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015655
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015656 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015657
15658 { }
15659};
15660
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015661static struct hda_verb alc861_toshiba_init_verbs[] = {
15662 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015663
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015664 { }
15665};
15666
15667/* toggle speaker-output according to the hp-jack state */
15668static void alc861_toshiba_automute(struct hda_codec *codec)
15669{
Wu Fengguang864f92b2009-11-18 12:38:02 +080015670 unsigned int present = snd_hda_jack_detect(codec, 0x0f);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015671
Takashi Iwai47fd8302007-08-10 17:11:07 +020015672 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
15673 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
15674 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
15675 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015676}
15677
15678static void alc861_toshiba_unsol_event(struct hda_codec *codec,
15679 unsigned int res)
15680{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015681 if ((res >> 26) == ALC880_HP_EVENT)
15682 alc861_toshiba_automute(codec);
15683}
15684
Sasha Alexandrdef319f2009-06-16 16:00:15 -040015685/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015686#define alc861_pcm_analog_playback alc880_pcm_analog_playback
15687#define alc861_pcm_analog_capture alc880_pcm_analog_capture
15688#define alc861_pcm_digital_playback alc880_pcm_digital_playback
15689#define alc861_pcm_digital_capture alc880_pcm_digital_capture
15690
15691
15692#define ALC861_DIGOUT_NID 0x07
15693
15694static struct hda_channel_mode alc861_8ch_modes[1] = {
15695 { 8, NULL }
15696};
15697
15698static hda_nid_t alc861_dac_nids[4] = {
15699 /* front, surround, clfe, side */
15700 0x03, 0x06, 0x05, 0x04
15701};
15702
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015703static hda_nid_t alc660_dac_nids[3] = {
15704 /* front, clfe, surround */
15705 0x03, 0x05, 0x06
15706};
15707
Kailang Yangdf694da2005-12-05 19:42:22 +010015708static hda_nid_t alc861_adc_nids[1] = {
15709 /* ADC0-2 */
15710 0x08,
15711};
15712
15713static struct hda_input_mux alc861_capture_source = {
15714 .num_items = 5,
15715 .items = {
15716 { "Mic", 0x0 },
15717 { "Front Mic", 0x3 },
15718 { "Line", 0x1 },
15719 { "CD", 0x4 },
15720 { "Mixer", 0x5 },
15721 },
15722};
15723
Takashi Iwai1c209302009-07-22 15:17:45 +020015724static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
15725{
15726 struct alc_spec *spec = codec->spec;
15727 hda_nid_t mix, srcs[5];
15728 int i, j, num;
15729
15730 if (snd_hda_get_connections(codec, pin, &mix, 1) != 1)
15731 return 0;
15732 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
15733 if (num < 0)
15734 return 0;
15735 for (i = 0; i < num; i++) {
15736 unsigned int type;
Takashi Iwaia22d5432009-07-27 12:54:26 +020015737 type = get_wcaps_type(get_wcaps(codec, srcs[i]));
Takashi Iwai1c209302009-07-22 15:17:45 +020015738 if (type != AC_WID_AUD_OUT)
15739 continue;
15740 for (j = 0; j < spec->multiout.num_dacs; j++)
15741 if (spec->multiout.dac_nids[j] == srcs[i])
15742 break;
15743 if (j >= spec->multiout.num_dacs)
15744 return srcs[i];
15745 }
15746 return 0;
15747}
15748
Kailang Yangdf694da2005-12-05 19:42:22 +010015749/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwai1c209302009-07-22 15:17:45 +020015750static int alc861_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015751 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010015752{
Takashi Iwai1c209302009-07-22 15:17:45 +020015753 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015754 int i;
Takashi Iwai1c209302009-07-22 15:17:45 +020015755 hda_nid_t nid, dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010015756
15757 spec->multiout.dac_nids = spec->private_dac_nids;
15758 for (i = 0; i < cfg->line_outs; i++) {
15759 nid = cfg->line_out_pins[i];
Takashi Iwai1c209302009-07-22 15:17:45 +020015760 dac = alc861_look_for_dac(codec, nid);
15761 if (!dac)
15762 continue;
15763 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010015764 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015765 return 0;
15766}
15767
Takashi Iwai1c209302009-07-22 15:17:45 +020015768static int alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
15769 hda_nid_t nid, unsigned int chs)
Kailang Yangdf694da2005-12-05 19:42:22 +010015770{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015771 return add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai1c209302009-07-22 15:17:45 +020015772 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
15773}
15774
15775/* add playback controls from the parsed DAC table */
15776static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
15777 const struct auto_pin_cfg *cfg)
15778{
15779 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015780 static const char *chname[4] = {
15781 "Front", "Surround", NULL /*CLFE*/, "Side"
15782 };
Kailang Yangdf694da2005-12-05 19:42:22 +010015783 hda_nid_t nid;
Takashi Iwai1c209302009-07-22 15:17:45 +020015784 int i, err;
15785
15786 if (cfg->line_outs == 1) {
15787 const char *pfx = NULL;
15788 if (!cfg->hp_outs)
15789 pfx = "Master";
15790 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
15791 pfx = "Speaker";
15792 if (pfx) {
15793 nid = spec->multiout.dac_nids[0];
15794 return alc861_create_out_sw(codec, pfx, nid, 3);
15795 }
15796 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015797
15798 for (i = 0; i < cfg->line_outs; i++) {
15799 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015800 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010015801 continue;
Takashi Iwai1c209302009-07-22 15:17:45 +020015802 if (i == 2) {
Kailang Yangdf694da2005-12-05 19:42:22 +010015803 /* Center/LFE */
Takashi Iwai1c209302009-07-22 15:17:45 +020015804 err = alc861_create_out_sw(codec, "Center", nid, 1);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015805 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015806 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015807 err = alc861_create_out_sw(codec, "LFE", nid, 2);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015808 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015809 return err;
15810 } else {
Takashi Iwai1c209302009-07-22 15:17:45 +020015811 err = alc861_create_out_sw(codec, chname[i], nid, 3);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015812 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015813 return err;
15814 }
15815 }
15816 return 0;
15817}
15818
Takashi Iwai1c209302009-07-22 15:17:45 +020015819static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010015820{
Takashi Iwai1c209302009-07-22 15:17:45 +020015821 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015822 int err;
15823 hda_nid_t nid;
15824
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015825 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010015826 return 0;
15827
15828 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
Takashi Iwai1c209302009-07-22 15:17:45 +020015829 nid = alc861_look_for_dac(codec, pin);
15830 if (nid) {
15831 err = alc861_create_out_sw(codec, "Headphone", nid, 3);
15832 if (err < 0)
15833 return err;
15834 spec->multiout.hp_nid = nid;
15835 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015836 }
15837 return 0;
15838}
15839
15840/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020015841static int alc861_auto_create_input_ctls(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015842 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010015843{
Takashi Iwai05f5f472009-08-25 13:10:18 +020015844 return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x08, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010015845}
15846
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015847static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
15848 hda_nid_t nid,
Takashi Iwai1c209302009-07-22 15:17:45 +020015849 int pin_type, hda_nid_t dac)
Kailang Yangdf694da2005-12-05 19:42:22 +010015850{
Takashi Iwai1c209302009-07-22 15:17:45 +020015851 hda_nid_t mix, srcs[5];
15852 int i, num;
15853
Jacek Luczak564c5be2008-05-03 18:41:23 +020015854 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
15855 pin_type);
Takashi Iwai1c209302009-07-22 15:17:45 +020015856 snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Jacek Luczak564c5be2008-05-03 18:41:23 +020015857 AMP_OUT_UNMUTE);
Takashi Iwai1c209302009-07-22 15:17:45 +020015858 if (snd_hda_get_connections(codec, nid, &mix, 1) != 1)
15859 return;
15860 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
15861 if (num < 0)
15862 return;
15863 for (i = 0; i < num; i++) {
15864 unsigned int mute;
15865 if (srcs[i] == dac || srcs[i] == 0x15)
15866 mute = AMP_IN_UNMUTE(i);
15867 else
15868 mute = AMP_IN_MUTE(i);
15869 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15870 mute);
15871 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015872}
15873
15874static void alc861_auto_init_multi_out(struct hda_codec *codec)
15875{
15876 struct alc_spec *spec = codec->spec;
15877 int i;
15878
15879 for (i = 0; i < spec->autocfg.line_outs; i++) {
15880 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015881 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010015882 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015883 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015884 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010015885 }
15886}
15887
15888static void alc861_auto_init_hp_out(struct hda_codec *codec)
15889{
15890 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015891
Takashi Iwai15870f02009-10-05 08:25:13 +020015892 if (spec->autocfg.hp_outs)
15893 alc861_auto_set_output_and_unmute(codec,
15894 spec->autocfg.hp_pins[0],
15895 PIN_HP,
Takashi Iwai1c209302009-07-22 15:17:45 +020015896 spec->multiout.hp_nid);
Takashi Iwai15870f02009-10-05 08:25:13 +020015897 if (spec->autocfg.speaker_outs)
15898 alc861_auto_set_output_and_unmute(codec,
15899 spec->autocfg.speaker_pins[0],
15900 PIN_OUT,
Takashi Iwai1c209302009-07-22 15:17:45 +020015901 spec->multiout.dac_nids[0]);
Kailang Yangdf694da2005-12-05 19:42:22 +010015902}
15903
15904static void alc861_auto_init_analog_input(struct hda_codec *codec)
15905{
15906 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020015907 struct auto_pin_cfg *cfg = &spec->autocfg;
Kailang Yangdf694da2005-12-05 19:42:22 +010015908 int i;
15909
Takashi Iwai66ceeb62010-08-30 13:05:52 +020015910 for (i = 0; i < cfg->num_inputs; i++) {
15911 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai23f0c042009-02-26 13:03:58 +010015912 if (nid >= 0x0c && nid <= 0x11)
Takashi Iwai30ea0982010-09-16 18:47:56 +020015913 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Kailang Yangdf694da2005-12-05 19:42:22 +010015914 }
15915}
15916
15917/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015918/* return 1 if successful, 0 if the proper config is not found,
15919 * or a negative error code
15920 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015921static int alc861_parse_auto_config(struct hda_codec *codec)
15922{
15923 struct alc_spec *spec = codec->spec;
15924 int err;
15925 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
15926
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015927 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
15928 alc861_ignore);
15929 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015930 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015931 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010015932 return 0; /* can't find valid BIOS pin config */
15933
Takashi Iwai1c209302009-07-22 15:17:45 +020015934 err = alc861_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015935 if (err < 0)
15936 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015937 err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015938 if (err < 0)
15939 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015940 err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015941 if (err < 0)
15942 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020015943 err = alc861_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015944 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015945 return err;
15946
15947 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
15948
Takashi Iwai757899a2010-07-30 10:48:14 +020015949 alc_auto_parse_digital(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015950
Takashi Iwai603c4012008-07-30 15:01:44 +020015951 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010015952 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010015953
Takashi Iwaid88897e2008-10-31 15:01:37 +010015954 add_verb(spec, alc861_auto_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +010015955
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020015956 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020015957 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010015958
15959 spec->adc_nids = alc861_adc_nids;
15960 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
Takashi Iwaib59bdf32009-08-11 09:47:30 +020015961 set_capture_mixer(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015962
Kailang Yang6227cdc2010-02-25 08:36:52 +010015963 alc_ssid_check(codec, 0x0e, 0x0f, 0x0b, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020015964
Kailang Yangdf694da2005-12-05 19:42:22 +010015965 return 1;
15966}
15967
Takashi Iwaiae6b8132006-03-03 16:47:17 +010015968/* additional initialization for auto-configuration model */
15969static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010015970{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015971 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015972 alc861_auto_init_multi_out(codec);
15973 alc861_auto_init_hp_out(codec);
15974 alc861_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020015975 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015976 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020015977 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015978}
15979
Takashi Iwaicb53c622007-08-10 17:21:45 +020015980#ifdef CONFIG_SND_HDA_POWER_SAVE
15981static struct hda_amp_list alc861_loopbacks[] = {
15982 { 0x15, HDA_INPUT, 0 },
15983 { 0x15, HDA_INPUT, 1 },
15984 { 0x15, HDA_INPUT, 2 },
15985 { 0x15, HDA_INPUT, 3 },
15986 { } /* end */
15987};
15988#endif
15989
Kailang Yangdf694da2005-12-05 19:42:22 +010015990
15991/*
15992 * configuration and preset
15993 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015994static const char *alc861_models[ALC861_MODEL_LAST] = {
15995 [ALC861_3ST] = "3stack",
15996 [ALC660_3ST] = "3stack-660",
15997 [ALC861_3ST_DIG] = "3stack-dig",
15998 [ALC861_6ST_DIG] = "6stack-dig",
15999 [ALC861_UNIWILL_M31] = "uniwill-m31",
16000 [ALC861_TOSHIBA] = "toshiba",
16001 [ALC861_ASUS] = "asus",
16002 [ALC861_ASUS_LAPTOP] = "asus-laptop",
16003 [ALC861_AUTO] = "auto",
16004};
16005
16006static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010016007 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010016008 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
16009 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
16010 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016011 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020016012 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010016013 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020016014 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
16015 * Any other models that need this preset?
16016 */
16017 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020016018 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
16019 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016020 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
16021 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
16022 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
16023 /* FIXME: the below seems conflict */
16024 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
16025 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
16026 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010016027 {}
16028};
16029
16030static struct alc_config_preset alc861_presets[] = {
16031 [ALC861_3ST] = {
16032 .mixers = { alc861_3ST_mixer },
16033 .init_verbs = { alc861_threestack_init_verbs },
16034 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16035 .dac_nids = alc861_dac_nids,
16036 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
16037 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020016038 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010016039 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16040 .adc_nids = alc861_adc_nids,
16041 .input_mux = &alc861_capture_source,
16042 },
16043 [ALC861_3ST_DIG] = {
16044 .mixers = { alc861_base_mixer },
16045 .init_verbs = { alc861_threestack_init_verbs },
16046 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16047 .dac_nids = alc861_dac_nids,
16048 .dig_out_nid = ALC861_DIGOUT_NID,
16049 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
16050 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020016051 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010016052 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16053 .adc_nids = alc861_adc_nids,
16054 .input_mux = &alc861_capture_source,
16055 },
16056 [ALC861_6ST_DIG] = {
16057 .mixers = { alc861_base_mixer },
16058 .init_verbs = { alc861_base_init_verbs },
16059 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16060 .dac_nids = alc861_dac_nids,
16061 .dig_out_nid = ALC861_DIGOUT_NID,
16062 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
16063 .channel_mode = alc861_8ch_modes,
16064 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16065 .adc_nids = alc861_adc_nids,
16066 .input_mux = &alc861_capture_source,
16067 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016068 [ALC660_3ST] = {
16069 .mixers = { alc861_3ST_mixer },
16070 .init_verbs = { alc861_threestack_init_verbs },
16071 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
16072 .dac_nids = alc660_dac_nids,
16073 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
16074 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020016075 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016076 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16077 .adc_nids = alc861_adc_nids,
16078 .input_mux = &alc861_capture_source,
16079 },
Takashi Iwai22309c32006-08-09 16:57:28 +020016080 [ALC861_UNIWILL_M31] = {
16081 .mixers = { alc861_uniwill_m31_mixer },
16082 .init_verbs = { alc861_uniwill_m31_init_verbs },
16083 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16084 .dac_nids = alc861_dac_nids,
16085 .dig_out_nid = ALC861_DIGOUT_NID,
16086 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
16087 .channel_mode = alc861_uniwill_m31_modes,
16088 .need_dac_fix = 1,
16089 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16090 .adc_nids = alc861_adc_nids,
16091 .input_mux = &alc861_capture_source,
16092 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020016093 [ALC861_TOSHIBA] = {
16094 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016095 .init_verbs = { alc861_base_init_verbs,
16096 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020016097 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16098 .dac_nids = alc861_dac_nids,
16099 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
16100 .channel_mode = alc883_3ST_2ch_modes,
16101 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16102 .adc_nids = alc861_adc_nids,
16103 .input_mux = &alc861_capture_source,
16104 .unsol_event = alc861_toshiba_unsol_event,
16105 .init_hook = alc861_toshiba_automute,
16106 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020016107 [ALC861_ASUS] = {
16108 .mixers = { alc861_asus_mixer },
16109 .init_verbs = { alc861_asus_init_verbs },
16110 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16111 .dac_nids = alc861_dac_nids,
16112 .dig_out_nid = ALC861_DIGOUT_NID,
16113 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
16114 .channel_mode = alc861_asus_modes,
16115 .need_dac_fix = 1,
16116 .hp_nid = 0x06,
16117 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16118 .adc_nids = alc861_adc_nids,
16119 .input_mux = &alc861_capture_source,
16120 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010016121 [ALC861_ASUS_LAPTOP] = {
16122 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
16123 .init_verbs = { alc861_asus_init_verbs,
16124 alc861_asus_laptop_init_verbs },
16125 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16126 .dac_nids = alc861_dac_nids,
16127 .dig_out_nid = ALC861_DIGOUT_NID,
16128 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
16129 .channel_mode = alc883_3ST_2ch_modes,
16130 .need_dac_fix = 1,
16131 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16132 .adc_nids = alc861_adc_nids,
16133 .input_mux = &alc861_capture_source,
16134 },
16135};
Kailang Yangdf694da2005-12-05 19:42:22 +010016136
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016137/* Pin config fixes */
16138enum {
16139 PINFIX_FSC_AMILO_PI1505,
16140};
16141
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016142static const struct alc_fixup alc861_fixups[] = {
16143 [PINFIX_FSC_AMILO_PI1505] = {
Takashi Iwai73413b12010-08-30 09:39:57 +020016144 .pins = (const struct alc_pincfg[]) {
16145 { 0x0b, 0x0221101f }, /* HP */
16146 { 0x0f, 0x90170310 }, /* speaker */
16147 { }
16148 }
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016149 },
16150};
16151
16152static struct snd_pci_quirk alc861_fixup_tbl[] = {
16153 SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
16154 {}
16155};
Kailang Yangdf694da2005-12-05 19:42:22 +010016156
16157static int patch_alc861(struct hda_codec *codec)
16158{
16159 struct alc_spec *spec;
16160 int board_config;
16161 int err;
16162
Robert P. J. Daydc041e02006-12-19 14:44:15 +010016163 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010016164 if (spec == NULL)
16165 return -ENOMEM;
16166
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016167 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010016168
Takashi Iwaif5fcc132006-11-24 17:07:44 +010016169 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
16170 alc861_models,
16171 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016172
Takashi Iwaif5fcc132006-11-24 17:07:44 +010016173 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020016174 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
16175 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010016176 board_config = ALC861_AUTO;
16177 }
16178
Takashi Iwai7fa90e82010-04-12 08:49:00 +020016179 if (board_config == ALC861_AUTO)
16180 alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups, 1);
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016181
Kailang Yangdf694da2005-12-05 19:42:22 +010016182 if (board_config == ALC861_AUTO) {
16183 /* automatic parse from the BIOS config */
16184 err = alc861_parse_auto_config(codec);
16185 if (err < 0) {
16186 alc_free(codec);
16187 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016188 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016189 printk(KERN_INFO
16190 "hda_codec: Cannot set up configuration "
16191 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010016192 board_config = ALC861_3ST_DIG;
16193 }
16194 }
16195
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090016196 err = snd_hda_attach_beep_device(codec, 0x23);
16197 if (err < 0) {
16198 alc_free(codec);
16199 return err;
16200 }
16201
Kailang Yangdf694da2005-12-05 19:42:22 +010016202 if (board_config != ALC861_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020016203 setup_preset(codec, &alc861_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010016204
Kailang Yangdf694da2005-12-05 19:42:22 +010016205 spec->stream_analog_playback = &alc861_pcm_analog_playback;
16206 spec->stream_analog_capture = &alc861_pcm_analog_capture;
16207
Kailang Yangdf694da2005-12-05 19:42:22 +010016208 spec->stream_digital_playback = &alc861_pcm_digital_playback;
16209 spec->stream_digital_capture = &alc861_pcm_digital_capture;
16210
Takashi Iwaic7a8eb12010-01-14 12:39:02 +010016211 if (!spec->cap_mixer)
16212 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010016213 set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
16214
Takashi Iwai2134ea42008-01-10 16:53:55 +010016215 spec->vmaster_nid = 0x03;
16216
Takashi Iwai7fa90e82010-04-12 08:49:00 +020016217 if (board_config == ALC861_AUTO)
16218 alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups, 0);
16219
Kailang Yangdf694da2005-12-05 19:42:22 +010016220 codec->patch_ops = alc_patch_ops;
Daniel T Chenc97259d2009-12-27 18:52:08 -050016221 if (board_config == ALC861_AUTO) {
Takashi Iwaiae6b8132006-03-03 16:47:17 +010016222 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020016223#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050016224 spec->power_hook = alc_power_eapd;
16225#endif
16226 }
16227#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaicb53c622007-08-10 17:21:45 +020016228 if (!spec->loopback.amplist)
16229 spec->loopback.amplist = alc861_loopbacks;
16230#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020016231
Kailang Yangdf694da2005-12-05 19:42:22 +010016232 return 0;
16233}
16234
16235/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016236 * ALC861-VD support
16237 *
16238 * Based on ALC882
16239 *
16240 * In addition, an independent DAC
16241 */
16242#define ALC861VD_DIGOUT_NID 0x06
16243
16244static hda_nid_t alc861vd_dac_nids[4] = {
16245 /* front, surr, clfe, side surr */
16246 0x02, 0x03, 0x04, 0x05
16247};
16248
16249/* dac_nids for ALC660vd are in a different order - according to
16250 * Realtek's driver.
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016251 * This should probably result in a different mixer for 6stack models
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016252 * of ALC660vd codecs, but for now there is only 3stack mixer
16253 * - and it is the same as in 861vd.
16254 * adc_nids in ALC660vd are (is) the same as in 861vd
16255 */
16256static hda_nid_t alc660vd_dac_nids[3] = {
16257 /* front, rear, clfe, rear_surr */
16258 0x02, 0x04, 0x03
16259};
16260
16261static hda_nid_t alc861vd_adc_nids[1] = {
16262 /* ADC0 */
16263 0x09,
16264};
16265
Takashi Iwaie1406342008-02-11 18:32:32 +010016266static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
16267
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016268/* input MUX */
16269/* FIXME: should be a matrix-type input source selection */
16270static struct hda_input_mux alc861vd_capture_source = {
16271 .num_items = 4,
16272 .items = {
16273 { "Mic", 0x0 },
16274 { "Front Mic", 0x1 },
16275 { "Line", 0x2 },
16276 { "CD", 0x4 },
16277 },
16278};
16279
Kailang Yang272a5272007-05-14 11:00:38 +020016280static struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010016281 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020016282 .items = {
Tobin Davisb419f342008-03-07 11:57:51 +010016283 { "Ext Mic", 0x0 },
16284 { "Int Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020016285 },
16286};
16287
Kailang Yangd1a991a2007-08-15 16:21:59 +020016288static struct hda_input_mux alc861vd_hp_capture_source = {
16289 .num_items = 2,
16290 .items = {
16291 { "Front Mic", 0x0 },
16292 { "ATAPI Mic", 0x1 },
16293 },
16294};
16295
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016296/*
16297 * 2ch mode
16298 */
16299static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
16300 { 2, NULL }
16301};
16302
16303/*
16304 * 6ch mode
16305 */
16306static struct hda_verb alc861vd_6stack_ch6_init[] = {
16307 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
16308 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16309 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16310 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16311 { } /* end */
16312};
16313
16314/*
16315 * 8ch mode
16316 */
16317static struct hda_verb alc861vd_6stack_ch8_init[] = {
16318 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16319 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16320 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16321 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16322 { } /* end */
16323};
16324
16325static struct hda_channel_mode alc861vd_6stack_modes[2] = {
16326 { 6, alc861vd_6stack_ch6_init },
16327 { 8, alc861vd_6stack_ch8_init },
16328};
16329
16330static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
16331 {
16332 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
16333 .name = "Channel Mode",
16334 .info = alc_ch_mode_info,
16335 .get = alc_ch_mode_get,
16336 .put = alc_ch_mode_put,
16337 },
16338 { } /* end */
16339};
16340
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016341/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
16342 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
16343 */
16344static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
16345 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16346 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16347
16348 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16349 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
16350
16351 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
16352 HDA_OUTPUT),
16353 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
16354 HDA_OUTPUT),
16355 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
16356 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
16357
16358 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
16359 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
16360
16361 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16362
16363 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
16364 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16365 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16366
16367 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
16368 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16369 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16370
16371 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16372 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16373
16374 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16375 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16376
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016377 { } /* end */
16378};
16379
16380static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
16381 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16382 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16383
16384 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16385
16386 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
16387 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16388 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16389
16390 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
16391 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16392 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16393
16394 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16395 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16396
16397 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16398 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16399
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016400 { } /* end */
16401};
16402
Kailang Yangbdd148a2007-05-08 15:19:08 +020016403static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
16404 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16405 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
16406 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
16407
16408 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16409
16410 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
16411 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16412 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16413
16414 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
16415 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16416 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16417
16418 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16419 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16420
16421 { } /* end */
16422};
16423
Tobin Davisb419f342008-03-07 11:57:51 +010016424/* Pin assignment: Speaker=0x14, HP = 0x15,
16425 * Ext Mic=0x18, Int Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020016426 */
16427static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010016428 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16429 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020016430 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16431 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisb419f342008-03-07 11:57:51 +010016432 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
16433 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16434 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16435 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
16436 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16437 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020016438 { } /* end */
16439};
16440
Kailang Yangd1a991a2007-08-15 16:21:59 +020016441/* Pin assignment: Speaker=0x14, Line-out = 0x15,
16442 * Front Mic=0x18, ATAPI Mic = 0x19,
16443 */
16444static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
16445 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16446 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16447 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16448 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
16449 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16450 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16451 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16452 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020016453
Kailang Yangd1a991a2007-08-15 16:21:59 +020016454 { } /* end */
16455};
16456
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016457/*
16458 * generic initialization of ADC, input mixers and output mixers
16459 */
16460static struct hda_verb alc861vd_volume_init_verbs[] = {
16461 /*
16462 * Unmute ADC0 and set the default input to mic-in
16463 */
16464 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
16465 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16466
16467 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
16468 * the analog-loopback mixer widget
16469 */
16470 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020016471 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16472 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16473 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16474 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16475 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016476
16477 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020016478 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16479 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16480 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016481 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016482
16483 /*
16484 * Set up output mixers (0x02 - 0x05)
16485 */
16486 /* set vol=0 to output mixers */
16487 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16488 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16489 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16490 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16491
16492 /* set up input amps for analog loopback */
16493 /* Amp Indices: DAC = 0, mixer = 1 */
16494 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16495 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16496 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16497 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16498 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16499 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16500 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16501 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16502
16503 { }
16504};
16505
16506/*
16507 * 3-stack pin configuration:
16508 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
16509 */
16510static struct hda_verb alc861vd_3stack_init_verbs[] = {
16511 /*
16512 * Set pin mode and muting
16513 */
16514 /* set front pin widgets 0x14 for output */
16515 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16516 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16517 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16518
16519 /* Mic (rear) pin: input vref at 80% */
16520 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16521 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16522 /* Front Mic pin: input vref at 80% */
16523 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16524 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16525 /* Line In pin: input */
16526 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16527 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16528 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16529 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16530 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16531 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16532 /* CD pin widget for input */
16533 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16534
16535 { }
16536};
16537
16538/*
16539 * 6-stack pin configuration:
16540 */
16541static struct hda_verb alc861vd_6stack_init_verbs[] = {
16542 /*
16543 * Set pin mode and muting
16544 */
16545 /* set front pin widgets 0x14 for output */
16546 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16547 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16548 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16549
16550 /* Rear Pin: output 1 (0x0d) */
16551 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16552 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16553 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
16554 /* CLFE Pin: output 2 (0x0e) */
16555 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16556 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16557 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
16558 /* Side Pin: output 3 (0x0f) */
16559 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16560 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16561 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
16562
16563 /* Mic (rear) pin: input vref at 80% */
16564 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16565 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16566 /* Front Mic pin: input vref at 80% */
16567 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16568 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16569 /* Line In pin: input */
16570 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16571 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16572 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16573 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16574 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16575 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16576 /* CD pin widget for input */
16577 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16578
16579 { }
16580};
16581
Kailang Yangbdd148a2007-05-08 15:19:08 +020016582static struct hda_verb alc861vd_eapd_verbs[] = {
16583 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16584 { }
16585};
16586
Kailang Yangf9423e72008-05-27 12:32:25 +020016587static struct hda_verb alc660vd_eapd_verbs[] = {
16588 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16589 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
16590 { }
16591};
16592
Kailang Yangbdd148a2007-05-08 15:19:08 +020016593static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
16594 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16595 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16596 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
16597 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020016598 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020016599 {}
16600};
16601
Kailang Yangbdd148a2007-05-08 15:19:08 +020016602static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
16603{
16604 unsigned int present;
16605 unsigned char bits;
16606
Wu Fengguang864f92b2009-11-18 12:38:02 +080016607 present = snd_hda_jack_detect(codec, 0x18);
Takashi Iwai47fd8302007-08-10 17:11:07 +020016608 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080016609
Takashi Iwai47fd8302007-08-10 17:11:07 +020016610 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
16611 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016612}
16613
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016614static void alc861vd_lenovo_setup(struct hda_codec *codec)
Kailang Yangbdd148a2007-05-08 15:19:08 +020016615{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016616 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016617 spec->autocfg.hp_pins[0] = 0x1b;
16618 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016619}
16620
16621static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
16622{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016623 alc_automute_amp(codec);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016624 alc861vd_lenovo_mic_automute(codec);
16625}
16626
16627static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
16628 unsigned int res)
16629{
16630 switch (res >> 26) {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016631 case ALC880_MIC_EVENT:
16632 alc861vd_lenovo_mic_automute(codec);
16633 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016634 default:
16635 alc_automute_amp_unsol_event(codec, res);
16636 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +020016637 }
16638}
16639
Kailang Yang272a5272007-05-14 11:00:38 +020016640static struct hda_verb alc861vd_dallas_verbs[] = {
16641 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16642 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16643 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16644 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16645
16646 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16647 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16648 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16649 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16650 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16651 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16652 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16653 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016654
Kailang Yang272a5272007-05-14 11:00:38 +020016655 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16656 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16657 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16658 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16659 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16660 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16661 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16662 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16663
16664 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16665 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16666 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16667 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16668 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16669 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16670 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16671 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16672
16673 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16674 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16675 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16676 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
16677
16678 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016679 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020016680 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16681
16682 { } /* end */
16683};
16684
16685/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016686static void alc861vd_dallas_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +020016687{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016688 struct alc_spec *spec = codec->spec;
Kailang Yang272a5272007-05-14 11:00:38 +020016689
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016690 spec->autocfg.hp_pins[0] = 0x15;
16691 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang272a5272007-05-14 11:00:38 +020016692}
16693
Takashi Iwaicb53c622007-08-10 17:21:45 +020016694#ifdef CONFIG_SND_HDA_POWER_SAVE
16695#define alc861vd_loopbacks alc880_loopbacks
16696#endif
16697
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016698/* pcm configuration: identical with ALC880 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016699#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
16700#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
16701#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
16702#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
16703
16704/*
16705 * configuration and preset
16706 */
16707static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
16708 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016709 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Takashi Iwai13c94742008-11-05 08:06:08 +010016710 [ALC660VD_ASUS_V1S] = "asus-v1s",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016711 [ALC861VD_3ST] = "3stack",
16712 [ALC861VD_3ST_DIG] = "3stack-digout",
16713 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020016714 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020016715 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016716 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016717 [ALC861VD_AUTO] = "auto",
16718};
16719
16720static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016721 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
16722 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010016723 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016724 /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */
Takashi Iwai13c94742008-11-05 08:06:08 +010016725 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
Mike Crash6963f842007-06-25 12:12:51 +020016726 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016727 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016728 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020016729 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Takashi Iwaice577e82009-08-03 08:23:52 +020016730 SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai542d7c62007-08-16 18:57:30 +020016731 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010016732 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020016733 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016734 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020016735 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016736 {}
16737};
16738
16739static struct alc_config_preset alc861vd_presets[] = {
16740 [ALC660VD_3ST] = {
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,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016746 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16747 .channel_mode = alc861vd_3stack_2ch_modes,
16748 .input_mux = &alc861vd_capture_source,
16749 },
Mike Crash6963f842007-06-25 12:12:51 +020016750 [ALC660VD_3ST_DIG] = {
16751 .mixers = { alc861vd_3st_mixer },
16752 .init_verbs = { alc861vd_volume_init_verbs,
16753 alc861vd_3stack_init_verbs },
16754 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16755 .dac_nids = alc660vd_dac_nids,
16756 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020016757 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16758 .channel_mode = alc861vd_3stack_2ch_modes,
16759 .input_mux = &alc861vd_capture_source,
16760 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016761 [ALC861VD_3ST] = {
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 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16768 .channel_mode = alc861vd_3stack_2ch_modes,
16769 .input_mux = &alc861vd_capture_source,
16770 },
16771 [ALC861VD_3ST_DIG] = {
16772 .mixers = { alc861vd_3st_mixer },
16773 .init_verbs = { alc861vd_volume_init_verbs,
16774 alc861vd_3stack_init_verbs },
16775 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16776 .dac_nids = alc861vd_dac_nids,
16777 .dig_out_nid = ALC861VD_DIGOUT_NID,
16778 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16779 .channel_mode = alc861vd_3stack_2ch_modes,
16780 .input_mux = &alc861vd_capture_source,
16781 },
16782 [ALC861VD_6ST_DIG] = {
16783 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
16784 .init_verbs = { alc861vd_volume_init_verbs,
16785 alc861vd_6stack_init_verbs },
16786 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16787 .dac_nids = alc861vd_dac_nids,
16788 .dig_out_nid = ALC861VD_DIGOUT_NID,
16789 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
16790 .channel_mode = alc861vd_6stack_modes,
16791 .input_mux = &alc861vd_capture_source,
16792 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020016793 [ALC861VD_LENOVO] = {
16794 .mixers = { alc861vd_lenovo_mixer },
16795 .init_verbs = { alc861vd_volume_init_verbs,
16796 alc861vd_3stack_init_verbs,
16797 alc861vd_eapd_verbs,
16798 alc861vd_lenovo_unsol_verbs },
16799 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16800 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016801 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16802 .channel_mode = alc861vd_3stack_2ch_modes,
16803 .input_mux = &alc861vd_capture_source,
16804 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016805 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016806 .init_hook = alc861vd_lenovo_init_hook,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016807 },
Kailang Yang272a5272007-05-14 11:00:38 +020016808 [ALC861VD_DALLAS] = {
16809 .mixers = { alc861vd_dallas_mixer },
16810 .init_verbs = { alc861vd_dallas_verbs },
16811 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16812 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020016813 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16814 .channel_mode = alc861vd_3stack_2ch_modes,
16815 .input_mux = &alc861vd_dallas_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016816 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016817 .setup = alc861vd_dallas_setup,
16818 .init_hook = alc_automute_amp,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016819 },
16820 [ALC861VD_HP] = {
16821 .mixers = { alc861vd_hp_mixer },
16822 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
16823 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16824 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016825 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016826 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16827 .channel_mode = alc861vd_3stack_2ch_modes,
16828 .input_mux = &alc861vd_hp_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016829 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016830 .setup = alc861vd_dallas_setup,
16831 .init_hook = alc_automute_amp,
Kailang Yangea1fb292008-08-26 12:58:38 +020016832 },
Takashi Iwai13c94742008-11-05 08:06:08 +010016833 [ALC660VD_ASUS_V1S] = {
16834 .mixers = { alc861vd_lenovo_mixer },
16835 .init_verbs = { alc861vd_volume_init_verbs,
16836 alc861vd_3stack_init_verbs,
16837 alc861vd_eapd_verbs,
16838 alc861vd_lenovo_unsol_verbs },
16839 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16840 .dac_nids = alc660vd_dac_nids,
16841 .dig_out_nid = ALC861VD_DIGOUT_NID,
16842 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16843 .channel_mode = alc861vd_3stack_2ch_modes,
16844 .input_mux = &alc861vd_capture_source,
16845 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016846 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016847 .init_hook = alc861vd_lenovo_init_hook,
Takashi Iwai13c94742008-11-05 08:06:08 +010016848 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016849};
16850
16851/*
16852 * BIOS auto configuration
16853 */
Takashi Iwai05f5f472009-08-25 13:10:18 +020016854static int alc861vd_auto_create_input_ctls(struct hda_codec *codec,
16855 const struct auto_pin_cfg *cfg)
16856{
Kailang Yang6227cdc2010-02-25 08:36:52 +010016857 return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x09, 0);
Takashi Iwai05f5f472009-08-25 13:10:18 +020016858}
16859
16860
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016861static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
16862 hda_nid_t nid, int pin_type, int dac_idx)
16863{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016864 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016865}
16866
16867static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
16868{
16869 struct alc_spec *spec = codec->spec;
16870 int i;
16871
16872 for (i = 0; i <= HDA_SIDE; i++) {
16873 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016874 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016875 if (nid)
16876 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016877 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016878 }
16879}
16880
16881
16882static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
16883{
16884 struct alc_spec *spec = codec->spec;
16885 hda_nid_t pin;
16886
16887 pin = spec->autocfg.hp_pins[0];
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016888 if (pin) /* connect to front and use dac 0 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016889 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016890 pin = spec->autocfg.speaker_pins[0];
16891 if (pin)
16892 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016893}
16894
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016895#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
16896
16897static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
16898{
16899 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020016900 struct auto_pin_cfg *cfg = &spec->autocfg;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016901 int i;
16902
Takashi Iwai66ceeb62010-08-30 13:05:52 +020016903 for (i = 0; i < cfg->num_inputs; i++) {
16904 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +020016905 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai30ea0982010-09-16 18:47:56 +020016906 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwaie82c0252009-03-23 15:17:38 +010016907 if (nid != ALC861VD_PIN_CD_NID &&
16908 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016909 snd_hda_codec_write(codec, nid, 0,
16910 AC_VERB_SET_AMP_GAIN_MUTE,
16911 AMP_OUT_MUTE);
16912 }
16913 }
16914}
16915
Takashi Iwaif511b012008-08-15 16:46:42 +020016916#define alc861vd_auto_init_input_src alc882_auto_init_input_src
16917
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016918#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
16919#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
16920
16921/* add playback controls from the parsed DAC table */
16922/* Based on ALC880 version. But ALC861VD has separate,
16923 * different NIDs for mute/unmute switch and volume control */
16924static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
16925 const struct auto_pin_cfg *cfg)
16926{
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016927 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
16928 hda_nid_t nid_v, nid_s;
16929 int i, err;
16930
16931 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016932 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016933 continue;
16934 nid_v = alc861vd_idx_to_mixer_vol(
16935 alc880_dac_to_idx(
16936 spec->multiout.dac_nids[i]));
16937 nid_s = alc861vd_idx_to_mixer_switch(
16938 alc880_dac_to_idx(
16939 spec->multiout.dac_nids[i]));
16940
16941 if (i == 2) {
16942 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016943 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
16944 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016945 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
16946 HDA_OUTPUT));
16947 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016948 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016949 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
16950 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016951 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
16952 HDA_OUTPUT));
16953 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016954 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016955 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
16956 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016957 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
16958 HDA_INPUT));
16959 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016960 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016961 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
16962 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016963 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
16964 HDA_INPUT));
16965 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016966 return err;
16967 } else {
Takashi Iwaia4fcd492009-08-25 16:12:15 +020016968 const char *pfx;
16969 if (cfg->line_outs == 1 &&
16970 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
16971 if (!cfg->hp_pins)
16972 pfx = "Speaker";
16973 else
16974 pfx = "PCM";
16975 } else
16976 pfx = chname[i];
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016977 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016978 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
16979 HDA_OUTPUT));
16980 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016981 return err;
Takashi Iwaia4fcd492009-08-25 16:12:15 +020016982 if (cfg->line_outs == 1 &&
16983 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
16984 pfx = "Speaker";
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016985 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016986 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016987 HDA_INPUT));
16988 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016989 return err;
16990 }
16991 }
16992 return 0;
16993}
16994
16995/* add playback controls for speaker and HP outputs */
16996/* Based on ALC880 version. But ALC861VD has separate,
16997 * different NIDs for mute/unmute switch and volume control */
16998static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
16999 hda_nid_t pin, const char *pfx)
17000{
17001 hda_nid_t nid_v, nid_s;
17002 int err;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017003
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017004 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017005 return 0;
17006
17007 if (alc880_is_fixed_pin(pin)) {
17008 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
17009 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017010 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017011 spec->multiout.hp_nid = nid_v;
17012 else
17013 spec->multiout.extra_out_nid[0] = nid_v;
17014 /* control HP volume/switch on the output mixer amp */
17015 nid_v = alc861vd_idx_to_mixer_vol(
17016 alc880_fixed_pin_idx(pin));
17017 nid_s = alc861vd_idx_to_mixer_switch(
17018 alc880_fixed_pin_idx(pin));
17019
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017020 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017021 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
17022 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017023 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017024 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017025 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
17026 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017027 return err;
17028 } else if (alc880_is_multi_pin(pin)) {
17029 /* set manual connection */
17030 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017031 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017032 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
17033 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017034 return err;
17035 }
17036 return 0;
17037}
17038
17039/* parse the BIOS configuration and set up the alc_spec
17040 * return 1 if successful, 0 if the proper config is not found,
17041 * or a negative error code
17042 * Based on ALC880 version - had to change it to override
17043 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
17044static int alc861vd_parse_auto_config(struct hda_codec *codec)
17045{
17046 struct alc_spec *spec = codec->spec;
17047 int err;
17048 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
17049
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017050 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
17051 alc861vd_ignore);
17052 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017053 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017054 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017055 return 0; /* can't find valid BIOS pin config */
17056
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017057 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
17058 if (err < 0)
17059 return err;
17060 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
17061 if (err < 0)
17062 return err;
17063 err = alc861vd_auto_create_extra_out(spec,
17064 spec->autocfg.speaker_pins[0],
17065 "Speaker");
17066 if (err < 0)
17067 return err;
17068 err = alc861vd_auto_create_extra_out(spec,
17069 spec->autocfg.hp_pins[0],
17070 "Headphone");
17071 if (err < 0)
17072 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020017073 err = alc861vd_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017074 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017075 return err;
17076
17077 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
17078
Takashi Iwai757899a2010-07-30 10:48:14 +020017079 alc_auto_parse_digital(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017080
Takashi Iwai603c4012008-07-30 15:01:44 +020017081 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010017082 add_mixer(spec, spec->kctls.list);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017083
Takashi Iwaid88897e2008-10-31 15:01:37 +010017084 add_verb(spec, alc861vd_volume_init_verbs);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017085
17086 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020017087 spec->input_mux = &spec->private_imux[0];
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017088
Takashi Iwai776e1842007-08-29 15:07:11 +020017089 err = alc_auto_add_mic_boost(codec);
17090 if (err < 0)
17091 return err;
17092
Kailang Yang6227cdc2010-02-25 08:36:52 +010017093 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020017094
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017095 return 1;
17096}
17097
17098/* additional initialization for auto-configuration model */
17099static void alc861vd_auto_init(struct hda_codec *codec)
17100{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017101 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017102 alc861vd_auto_init_multi_out(codec);
17103 alc861vd_auto_init_hp_out(codec);
17104 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020017105 alc861vd_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020017106 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017107 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020017108 alc_inithook(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017109}
17110
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017111enum {
17112 ALC660VD_FIX_ASUS_GPIO1
17113};
17114
17115/* reset GPIO1 */
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017116static const struct alc_fixup alc861vd_fixups[] = {
17117 [ALC660VD_FIX_ASUS_GPIO1] = {
Takashi Iwai73413b12010-08-30 09:39:57 +020017118 .verbs = (const struct hda_verb[]) {
17119 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
17120 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
17121 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
17122 { }
17123 }
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017124 },
17125};
17126
17127static struct snd_pci_quirk alc861vd_fixup_tbl[] = {
17128 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
17129 {}
17130};
17131
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017132static int patch_alc861vd(struct hda_codec *codec)
17133{
17134 struct alc_spec *spec;
17135 int err, board_config;
17136
17137 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
17138 if (spec == NULL)
17139 return -ENOMEM;
17140
17141 codec->spec = spec;
17142
17143 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
17144 alc861vd_models,
17145 alc861vd_cfg_tbl);
17146
17147 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020017148 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
17149 codec->chip_name);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017150 board_config = ALC861VD_AUTO;
17151 }
17152
Takashi Iwai7fa90e82010-04-12 08:49:00 +020017153 if (board_config == ALC861VD_AUTO)
17154 alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups, 1);
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017155
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017156 if (board_config == ALC861VD_AUTO) {
17157 /* automatic parse from the BIOS config */
17158 err = alc861vd_parse_auto_config(codec);
17159 if (err < 0) {
17160 alc_free(codec);
17161 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017162 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017163 printk(KERN_INFO
17164 "hda_codec: Cannot set up configuration "
17165 "from BIOS. Using base mode...\n");
17166 board_config = ALC861VD_3ST;
17167 }
17168 }
17169
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090017170 err = snd_hda_attach_beep_device(codec, 0x23);
17171 if (err < 0) {
17172 alc_free(codec);
17173 return err;
17174 }
17175
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017176 if (board_config != ALC861VD_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020017177 setup_preset(codec, &alc861vd_presets[board_config]);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017178
Kailang Yang2f893282008-05-27 12:14:47 +020017179 if (codec->vendor_id == 0x10ec0660) {
Kailang Yangf9423e72008-05-27 12:32:25 +020017180 /* always turn on EAPD */
Takashi Iwaid88897e2008-10-31 15:01:37 +010017181 add_verb(spec, alc660vd_eapd_verbs);
Kailang Yang2f893282008-05-27 12:14:47 +020017182 }
17183
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017184 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
17185 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
17186
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017187 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
17188 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
17189
Takashi Iwaidd704692009-08-11 08:45:11 +020017190 if (!spec->adc_nids) {
17191 spec->adc_nids = alc861vd_adc_nids;
17192 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
17193 }
17194 if (!spec->capsrc_nids)
17195 spec->capsrc_nids = alc861vd_capsrc_nids;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017196
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017197 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010017198 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017199
Takashi Iwai2134ea42008-01-10 16:53:55 +010017200 spec->vmaster_nid = 0x02;
17201
Takashi Iwai7fa90e82010-04-12 08:49:00 +020017202 if (board_config == ALC861VD_AUTO)
17203 alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups, 0);
17204
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017205 codec->patch_ops = alc_patch_ops;
17206
17207 if (board_config == ALC861VD_AUTO)
17208 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020017209#ifdef CONFIG_SND_HDA_POWER_SAVE
17210 if (!spec->loopback.amplist)
17211 spec->loopback.amplist = alc861vd_loopbacks;
17212#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017213
17214 return 0;
17215}
17216
17217/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017218 * ALC662 support
17219 *
17220 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
17221 * configuration. Each pin widget can choose any input DACs and a mixer.
17222 * Each ADC is connected from a mixer of all inputs. This makes possible
17223 * 6-channel independent captures.
17224 *
17225 * In addition, an independent DAC for the multi-playback (not used in this
17226 * driver yet).
17227 */
17228#define ALC662_DIGOUT_NID 0x06
17229#define ALC662_DIGIN_NID 0x0a
17230
17231static hda_nid_t alc662_dac_nids[4] = {
17232 /* front, rear, clfe, rear_surr */
17233 0x02, 0x03, 0x04
17234};
17235
Kailang Yang622e84c2009-04-21 07:39:04 +020017236static hda_nid_t alc272_dac_nids[2] = {
17237 0x02, 0x03
17238};
17239
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017240static hda_nid_t alc662_adc_nids[2] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017241 /* ADC1-2 */
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017242 0x09, 0x08
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017243};
Takashi Iwaie1406342008-02-11 18:32:32 +010017244
Kailang Yang622e84c2009-04-21 07:39:04 +020017245static hda_nid_t alc272_adc_nids[1] = {
17246 /* ADC1-2 */
17247 0x08,
17248};
17249
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017250static hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 };
Kailang Yang622e84c2009-04-21 07:39:04 +020017251static hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
17252
Takashi Iwaie1406342008-02-11 18:32:32 +010017253
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017254/* input MUX */
17255/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017256static struct hda_input_mux alc662_capture_source = {
17257 .num_items = 4,
17258 .items = {
17259 { "Mic", 0x0 },
17260 { "Front Mic", 0x1 },
17261 { "Line", 0x2 },
17262 { "CD", 0x4 },
17263 },
17264};
17265
17266static struct hda_input_mux alc662_lenovo_101e_capture_source = {
17267 .num_items = 2,
17268 .items = {
17269 { "Mic", 0x1 },
17270 { "Line", 0x2 },
17271 },
17272};
Kailang Yang291702f2007-10-16 14:28:03 +020017273
Kailang Yang6dda9f42008-05-27 12:05:31 +020017274static struct hda_input_mux alc663_capture_source = {
17275 .num_items = 3,
17276 .items = {
17277 { "Mic", 0x0 },
17278 { "Front Mic", 0x1 },
17279 { "Line", 0x2 },
17280 },
17281};
17282
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017283#if 0 /* set to 1 for testing other input sources below */
Chris Pockelé9541ba12009-05-12 08:08:53 +020017284static struct hda_input_mux alc272_nc10_capture_source = {
17285 .num_items = 16,
17286 .items = {
17287 { "Autoselect Mic", 0x0 },
17288 { "Internal Mic", 0x1 },
17289 { "In-0x02", 0x2 },
17290 { "In-0x03", 0x3 },
17291 { "In-0x04", 0x4 },
17292 { "In-0x05", 0x5 },
17293 { "In-0x06", 0x6 },
17294 { "In-0x07", 0x7 },
17295 { "In-0x08", 0x8 },
17296 { "In-0x09", 0x9 },
17297 { "In-0x0a", 0x0a },
17298 { "In-0x0b", 0x0b },
17299 { "In-0x0c", 0x0c },
17300 { "In-0x0d", 0x0d },
17301 { "In-0x0e", 0x0e },
17302 { "In-0x0f", 0x0f },
17303 },
17304};
17305#endif
17306
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017307/*
17308 * 2ch mode
17309 */
17310static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
17311 { 2, NULL }
17312};
17313
17314/*
17315 * 2ch mode
17316 */
17317static struct hda_verb alc662_3ST_ch2_init[] = {
17318 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
17319 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
17320 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
17321 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
17322 { } /* end */
17323};
17324
17325/*
17326 * 6ch mode
17327 */
17328static struct hda_verb alc662_3ST_ch6_init[] = {
17329 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17330 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
17331 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
17332 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17333 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
17334 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
17335 { } /* end */
17336};
17337
17338static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
17339 { 2, alc662_3ST_ch2_init },
17340 { 6, alc662_3ST_ch6_init },
17341};
17342
17343/*
17344 * 2ch mode
17345 */
17346static struct hda_verb alc662_sixstack_ch6_init[] = {
17347 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
17348 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
17349 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17350 { } /* end */
17351};
17352
17353/*
17354 * 6ch mode
17355 */
17356static struct hda_verb alc662_sixstack_ch8_init[] = {
17357 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17358 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17359 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17360 { } /* end */
17361};
17362
17363static struct hda_channel_mode alc662_5stack_modes[2] = {
17364 { 2, alc662_sixstack_ch6_init },
17365 { 6, alc662_sixstack_ch8_init },
17366};
17367
17368/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
17369 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
17370 */
17371
17372static struct snd_kcontrol_new alc662_base_mixer[] = {
17373 /* output mixer control */
17374 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017375 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017376 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017377 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017378 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17379 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017380 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
17381 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017382 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17383
17384 /*Input mixer control */
17385 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
17386 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
17387 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
17388 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
17389 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
17390 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
17391 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
17392 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017393 { } /* end */
17394};
17395
17396static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
17397 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017398 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017399 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17400 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
17401 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
17402 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17403 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17404 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17405 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17406 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17407 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017408 { } /* end */
17409};
17410
17411static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
17412 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017413 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017414 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017415 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017416 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17417 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017418 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
17419 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017420 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17421 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
17422 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
17423 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17424 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17425 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17426 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17427 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17428 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017429 { } /* end */
17430};
17431
17432static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
17433 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17434 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010017435 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17436 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017437 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17438 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17439 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17440 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17441 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017442 { } /* end */
17443};
17444
Kailang Yang291702f2007-10-16 14:28:03 +020017445static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020017446 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17447 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang291702f2007-10-16 14:28:03 +020017448
17449 HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
17450 HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17451 HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17452
17453 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
17454 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17455 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17456 { } /* end */
17457};
17458
Kailang Yang8c427222008-01-10 13:03:59 +010017459static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020017460 ALC262_HIPPO_MASTER_SWITCH,
17461 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017462 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017463 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17464 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017465 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
17466 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17467 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17468 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17469 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17470 { } /* end */
17471};
17472
Kailang Yangf1d4e282008-08-26 14:03:29 +020017473static struct hda_bind_ctls alc663_asus_bind_master_vol = {
17474 .ops = &snd_hda_bind_vol,
17475 .values = {
17476 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17477 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
17478 0
17479 },
17480};
17481
17482static struct hda_bind_ctls alc663_asus_one_bind_switch = {
17483 .ops = &snd_hda_bind_sw,
17484 .values = {
17485 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17486 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17487 0
17488 },
17489};
17490
Kailang Yang6dda9f42008-05-27 12:05:31 +020017491static struct snd_kcontrol_new alc663_m51va_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017492 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17493 HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
17494 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17495 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17496 { } /* end */
17497};
17498
17499static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
17500 .ops = &snd_hda_bind_sw,
17501 .values = {
17502 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17503 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17504 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17505 0
17506 },
17507};
17508
17509static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
17510 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17511 HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
17512 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17513 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17514 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17515 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17516
17517 { } /* end */
17518};
17519
17520static struct hda_bind_ctls alc663_asus_four_bind_switch = {
17521 .ops = &snd_hda_bind_sw,
17522 .values = {
17523 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17524 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17525 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17526 0
17527 },
17528};
17529
17530static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
17531 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17532 HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
17533 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17534 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17535 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17536 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17537 { } /* end */
17538};
17539
17540static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017541 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17542 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017543 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17544 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17545 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17546 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17547 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17548 { } /* end */
17549};
17550
17551static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
17552 .ops = &snd_hda_bind_vol,
17553 .values = {
17554 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17555 HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
17556 0
17557 },
17558};
17559
17560static struct hda_bind_ctls alc663_asus_two_bind_switch = {
17561 .ops = &snd_hda_bind_sw,
17562 .values = {
17563 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17564 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
17565 0
17566 },
17567};
17568
17569static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
17570 HDA_BIND_VOL("Master Playback Volume",
17571 &alc663_asus_two_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),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017574 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 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 Yangf1d4e282008-08-26 14:03:29 +020017577 { } /* end */
17578};
17579
17580static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
17581 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17582 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17583 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17584 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17585 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17586 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017587 { } /* end */
17588};
17589
17590static struct snd_kcontrol_new alc663_g71v_mixer[] = {
17591 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17592 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17593 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17594 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17595 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17596
17597 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17598 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17599 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17600 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17601 { } /* end */
17602};
17603
17604static struct snd_kcontrol_new alc663_g50v_mixer[] = {
17605 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17606 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17607 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17608
17609 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17610 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17611 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17612 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17613 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17614 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17615 { } /* end */
17616};
17617
Kailang Yangebb83ee2009-12-17 12:23:00 +010017618static struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = {
17619 .ops = &snd_hda_bind_sw,
17620 .values = {
17621 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17622 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17623 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17624 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17625 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17626 0
17627 },
17628};
17629
17630static struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = {
17631 .ops = &snd_hda_bind_sw,
17632 .values = {
17633 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17634 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17635 0
17636 },
17637};
17638
17639static struct snd_kcontrol_new alc663_mode7_mixer[] = {
17640 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17641 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17642 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17643 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17644 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17645 HDA_CODEC_VOLUME("IntMic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17646 HDA_CODEC_MUTE("IntMic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17647 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17648 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17649 { } /* end */
17650};
17651
17652static struct snd_kcontrol_new alc663_mode8_mixer[] = {
17653 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17654 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17655 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17656 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17657 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17658 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17659 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17660 { } /* end */
17661};
17662
17663
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017664static struct snd_kcontrol_new alc662_chmode_mixer[] = {
17665 {
17666 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
17667 .name = "Channel Mode",
17668 .info = alc_ch_mode_info,
17669 .get = alc_ch_mode_get,
17670 .put = alc_ch_mode_put,
17671 },
17672 { } /* end */
17673};
17674
17675static struct hda_verb alc662_init_verbs[] = {
17676 /* ADC: mute amp left and right */
17677 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17678 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017679
Kailang Yangb60dd392007-09-20 12:50:29 +020017680 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17681 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17682 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17683 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17684 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17685 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017686
17687 /* Front Pin: output 0 (0x0c) */
17688 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17689 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17690
17691 /* Rear Pin: output 1 (0x0d) */
17692 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17693 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17694
17695 /* CLFE Pin: output 2 (0x0e) */
17696 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17697 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17698
17699 /* Mic (rear) pin: input vref at 80% */
17700 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17701 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17702 /* Front Mic pin: input vref at 80% */
17703 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17704 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17705 /* Line In pin: input */
17706 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17707 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17708 /* Line-2 In: Headphone output (output 0 - 0x0c) */
17709 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17710 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17711 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
17712 /* CD pin widget for input */
17713 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17714
17715 /* FIXME: use matrix-type input source selection */
17716 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
17717 /* Input mixer */
17718 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang291702f2007-10-16 14:28:03 +020017719 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017720
17721 /* always trun on EAPD */
17722 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
17723 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
17724
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017725 { }
17726};
17727
Kailang Yangcec27c82010-02-04 14:18:18 +010017728static struct hda_verb alc663_init_verbs[] = {
17729 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17730 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17731 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17732 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17733 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17734 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17735 { }
17736};
17737
17738static struct hda_verb alc272_init_verbs[] = {
17739 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17740 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17741 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17742 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17743 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17744 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17745 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17746 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17747 { }
17748};
17749
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017750static struct hda_verb alc662_sue_init_verbs[] = {
17751 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
17752 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020017753 {}
17754};
17755
17756static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
17757 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17758 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17759 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017760};
17761
Kailang Yang8c427222008-01-10 13:03:59 +010017762/* Set Unsolicited Event*/
17763static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
17764 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17765 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17766 {}
17767};
17768
Kailang Yang6dda9f42008-05-27 12:05:31 +020017769static struct hda_verb alc663_m51va_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017770 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17771 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017772 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17773 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf1d4e282008-08-26 14:03:29 +020017774 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17775 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17776 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017777 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17778 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17779 {}
17780};
17781
Kailang Yangf1d4e282008-08-26 14:03:29 +020017782static struct hda_verb alc663_21jd_amic_init_verbs[] = {
17783 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17784 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17785 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17786 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17787 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17788 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17789 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17790 {}
17791};
17792
17793static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
17794 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17795 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17796 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17797 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17798 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17799 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17800 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17801 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17802 {}
17803};
17804
17805static struct hda_verb alc663_15jd_amic_init_verbs[] = {
17806 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17807 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17808 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17809 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17810 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17811 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17812 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17813 {}
17814};
17815
17816static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
17817 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17818 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17819 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17820 {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
17821 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17822 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17823 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
17824 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17825 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17826 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17827 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17828 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17829 {}
17830};
17831
17832static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
17833 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17834 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17835 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17836 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17837 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17838 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17839 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17840 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17841 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17842 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17843 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17844 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17845 {}
17846};
17847
Kailang Yang6dda9f42008-05-27 12:05:31 +020017848static struct hda_verb alc663_g71v_init_verbs[] = {
17849 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17850 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
17851 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
17852
17853 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17854 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17855 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17856
17857 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
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
17863static struct hda_verb alc663_g50v_init_verbs[] = {
17864 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17865 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17866 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17867
17868 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17869 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17870 {}
17871};
17872
Kailang Yangf1d4e282008-08-26 14:03:29 +020017873static struct hda_verb alc662_ecs_init_verbs[] = {
17874 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
17875 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17876 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17877 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17878 {}
17879};
17880
Kailang Yang622e84c2009-04-21 07:39:04 +020017881static struct hda_verb alc272_dell_zm1_init_verbs[] = {
17882 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17883 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17884 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17885 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17886 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17887 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17888 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17889 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17890 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17891 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17892 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17893 {}
17894};
17895
17896static struct hda_verb alc272_dell_init_verbs[] = {
17897 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17898 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17899 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17900 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17901 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17902 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17903 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17904 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17905 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17906 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17907 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17908 {}
17909};
17910
Kailang Yangebb83ee2009-12-17 12:23:00 +010017911static struct hda_verb alc663_mode7_init_verbs[] = {
17912 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17913 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17914 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17915 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17916 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17917 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17918 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
17919 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17920 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17921 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17922 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17923 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17924 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17925 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17926 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17927 {}
17928};
17929
17930static struct hda_verb alc663_mode8_init_verbs[] = {
17931 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17932 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17933 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17934 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
17935 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17936 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17937 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17938 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17939 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17940 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17941 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17942 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17943 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17944 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17945 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17946 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17947 {}
17948};
17949
Kailang Yangf1d4e282008-08-26 14:03:29 +020017950static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
17951 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
17952 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
17953 { } /* end */
17954};
17955
Kailang Yang622e84c2009-04-21 07:39:04 +020017956static struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
17957 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
17958 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
17959 { } /* end */
17960};
17961
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017962static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
17963{
17964 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017965 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017966
Wu Fengguang864f92b2009-11-18 12:38:02 +080017967 present = snd_hda_jack_detect(codec, 0x14);
Takashi Iwai47fd8302007-08-10 17:11:07 +020017968 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080017969
Takashi Iwai47fd8302007-08-10 17:11:07 +020017970 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
17971 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017972}
17973
17974static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
17975{
17976 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017977 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017978
Wu Fengguang864f92b2009-11-18 12:38:02 +080017979 present = snd_hda_jack_detect(codec, 0x1b);
Takashi Iwai47fd8302007-08-10 17:11:07 +020017980 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080017981
Takashi Iwai47fd8302007-08-10 17:11:07 +020017982 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
17983 HDA_AMP_MUTE, bits);
17984 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
17985 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017986}
17987
17988static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
17989 unsigned int res)
17990{
17991 if ((res >> 26) == ALC880_HP_EVENT)
17992 alc662_lenovo_101e_all_automute(codec);
17993 if ((res >> 26) == ALC880_FRONT_EVENT)
17994 alc662_lenovo_101e_ispeaker_automute(codec);
17995}
17996
Kailang Yang291702f2007-10-16 14:28:03 +020017997/* unsolicited event for HP jack sensing */
17998static void alc662_eeepc_unsol_event(struct hda_codec *codec,
17999 unsigned int res)
18000{
Kailang Yang291702f2007-10-16 14:28:03 +020018001 if ((res >> 26) == ALC880_MIC_EVENT)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018002 alc_mic_automute(codec);
Takashi Iwai42171c12009-05-08 14:11:43 +020018003 else
18004 alc262_hippo_unsol_event(codec, res);
Kailang Yang291702f2007-10-16 14:28:03 +020018005}
18006
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018007static void alc662_eeepc_setup(struct hda_codec *codec)
Kailang Yang291702f2007-10-16 14:28:03 +020018008{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018009 struct alc_spec *spec = codec->spec;
18010
18011 alc262_hippo1_setup(codec);
18012 spec->ext_mic.pin = 0x18;
18013 spec->ext_mic.mux_idx = 0;
18014 spec->int_mic.pin = 0x19;
18015 spec->int_mic.mux_idx = 1;
18016 spec->auto_mic = 1;
Kailang Yang291702f2007-10-16 14:28:03 +020018017}
18018
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018019static void alc662_eeepc_inithook(struct hda_codec *codec)
18020{
18021 alc262_hippo_automute(codec);
18022 alc_mic_automute(codec);
18023}
18024
18025static void alc662_eeepc_ep20_setup(struct hda_codec *codec)
Kailang Yang8c427222008-01-10 13:03:59 +010018026{
Takashi Iwai42171c12009-05-08 14:11:43 +020018027 struct alc_spec *spec = codec->spec;
18028
18029 spec->autocfg.hp_pins[0] = 0x14;
18030 spec->autocfg.speaker_pins[0] = 0x1b;
Kailang Yang8c427222008-01-10 13:03:59 +010018031}
18032
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018033#define alc662_eeepc_ep20_inithook alc262_hippo_master_update
18034
Kailang Yang6dda9f42008-05-27 12:05:31 +020018035static void alc663_m51va_speaker_automute(struct hda_codec *codec)
18036{
18037 unsigned int present;
18038 unsigned char bits;
18039
Wu Fengguang864f92b2009-11-18 12:38:02 +080018040 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018041 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yangf1d4e282008-08-26 14:03:29 +020018042 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018043 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018044 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018045 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018046}
18047
18048static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
18049{
18050 unsigned int present;
18051 unsigned char bits;
18052
Wu Fengguang864f92b2009-11-18 12:38:02 +080018053 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018054 bits = present ? HDA_AMP_MUTE : 0;
18055 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018056 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018057 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018058 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018059 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018060 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018061 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018062 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018063}
18064
18065static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
18066{
18067 unsigned int present;
18068 unsigned char bits;
18069
Wu Fengguang864f92b2009-11-18 12:38:02 +080018070 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018071 bits = present ? HDA_AMP_MUTE : 0;
18072 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018073 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018074 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018075 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018076 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018077 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018078 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018079 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018080}
18081
18082static void alc662_f5z_speaker_automute(struct hda_codec *codec)
18083{
18084 unsigned int present;
18085 unsigned char bits;
18086
Wu Fengguang864f92b2009-11-18 12:38:02 +080018087 present = snd_hda_jack_detect(codec, 0x1b);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018088 bits = present ? 0 : PIN_OUT;
18089 snd_hda_codec_write(codec, 0x14, 0,
18090 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
18091}
18092
18093static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
18094{
18095 unsigned int present1, present2;
18096
Wu Fengguang864f92b2009-11-18 12:38:02 +080018097 present1 = snd_hda_jack_detect(codec, 0x21);
18098 present2 = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018099
18100 if (present1 || present2) {
18101 snd_hda_codec_write_cache(codec, 0x14, 0,
18102 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
18103 } else {
18104 snd_hda_codec_write_cache(codec, 0x14, 0,
18105 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
18106 }
18107}
18108
18109static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
18110{
18111 unsigned int present1, present2;
18112
Wu Fengguang864f92b2009-11-18 12:38:02 +080018113 present1 = snd_hda_jack_detect(codec, 0x1b);
18114 present2 = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018115
18116 if (present1 || present2) {
18117 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018118 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018119 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018120 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018121 } else {
18122 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018123 HDA_AMP_MUTE, 0);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018124 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018125 HDA_AMP_MUTE, 0);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018126 }
Kailang Yang6dda9f42008-05-27 12:05:31 +020018127}
18128
Kailang Yangebb83ee2009-12-17 12:23:00 +010018129static void alc663_two_hp_m7_speaker_automute(struct hda_codec *codec)
18130{
18131 unsigned int present1, present2;
18132
18133 present1 = snd_hda_codec_read(codec, 0x1b, 0,
18134 AC_VERB_GET_PIN_SENSE, 0)
18135 & AC_PINSENSE_PRESENCE;
18136 present2 = snd_hda_codec_read(codec, 0x21, 0,
18137 AC_VERB_GET_PIN_SENSE, 0)
18138 & AC_PINSENSE_PRESENCE;
18139
18140 if (present1 || present2) {
18141 snd_hda_codec_write_cache(codec, 0x14, 0,
18142 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
18143 snd_hda_codec_write_cache(codec, 0x17, 0,
18144 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
18145 } else {
18146 snd_hda_codec_write_cache(codec, 0x14, 0,
18147 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
18148 snd_hda_codec_write_cache(codec, 0x17, 0,
18149 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
18150 }
18151}
18152
18153static void alc663_two_hp_m8_speaker_automute(struct hda_codec *codec)
18154{
18155 unsigned int present1, present2;
18156
18157 present1 = snd_hda_codec_read(codec, 0x21, 0,
18158 AC_VERB_GET_PIN_SENSE, 0)
18159 & AC_PINSENSE_PRESENCE;
18160 present2 = snd_hda_codec_read(codec, 0x15, 0,
18161 AC_VERB_GET_PIN_SENSE, 0)
18162 & AC_PINSENSE_PRESENCE;
18163
18164 if (present1 || present2) {
18165 snd_hda_codec_write_cache(codec, 0x14, 0,
18166 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
18167 snd_hda_codec_write_cache(codec, 0x17, 0,
18168 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
18169 } else {
18170 snd_hda_codec_write_cache(codec, 0x14, 0,
18171 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
18172 snd_hda_codec_write_cache(codec, 0x17, 0,
18173 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
18174 }
18175}
18176
Kailang Yang6dda9f42008-05-27 12:05:31 +020018177static void alc663_m51va_unsol_event(struct hda_codec *codec,
18178 unsigned int res)
18179{
18180 switch (res >> 26) {
18181 case ALC880_HP_EVENT:
18182 alc663_m51va_speaker_automute(codec);
18183 break;
18184 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018185 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018186 break;
18187 }
18188}
18189
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018190static void alc663_m51va_setup(struct hda_codec *codec)
18191{
18192 struct alc_spec *spec = codec->spec;
18193 spec->ext_mic.pin = 0x18;
18194 spec->ext_mic.mux_idx = 0;
18195 spec->int_mic.pin = 0x12;
Kailang Yangebb83ee2009-12-17 12:23:00 +010018196 spec->int_mic.mux_idx = 9;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018197 spec->auto_mic = 1;
18198}
18199
Kailang Yang6dda9f42008-05-27 12:05:31 +020018200static void alc663_m51va_inithook(struct hda_codec *codec)
18201{
18202 alc663_m51va_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018203 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018204}
18205
Kailang Yangf1d4e282008-08-26 14:03:29 +020018206/* ***************** Mode1 ******************************/
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018207#define alc663_mode1_unsol_event alc663_m51va_unsol_event
Kailang Yangebb83ee2009-12-17 12:23:00 +010018208
18209static void alc663_mode1_setup(struct hda_codec *codec)
18210{
18211 struct alc_spec *spec = codec->spec;
18212 spec->ext_mic.pin = 0x18;
18213 spec->ext_mic.mux_idx = 0;
18214 spec->int_mic.pin = 0x19;
18215 spec->int_mic.mux_idx = 1;
18216 spec->auto_mic = 1;
18217}
18218
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018219#define alc663_mode1_inithook alc663_m51va_inithook
Kailang Yangf1d4e282008-08-26 14:03:29 +020018220
Kailang Yangf1d4e282008-08-26 14:03:29 +020018221/* ***************** Mode2 ******************************/
18222static void alc662_mode2_unsol_event(struct hda_codec *codec,
18223 unsigned int res)
18224{
18225 switch (res >> 26) {
18226 case ALC880_HP_EVENT:
18227 alc662_f5z_speaker_automute(codec);
18228 break;
18229 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018230 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018231 break;
18232 }
18233}
18234
Kailang Yangebb83ee2009-12-17 12:23:00 +010018235#define alc662_mode2_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018236
Kailang Yangf1d4e282008-08-26 14:03:29 +020018237static void alc662_mode2_inithook(struct hda_codec *codec)
18238{
18239 alc662_f5z_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018240 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018241}
18242/* ***************** Mode3 ******************************/
18243static void alc663_mode3_unsol_event(struct hda_codec *codec,
18244 unsigned int res)
18245{
18246 switch (res >> 26) {
18247 case ALC880_HP_EVENT:
18248 alc663_two_hp_m1_speaker_automute(codec);
18249 break;
18250 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018251 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018252 break;
18253 }
18254}
18255
Kailang Yangebb83ee2009-12-17 12:23:00 +010018256#define alc663_mode3_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018257
Kailang Yangf1d4e282008-08-26 14:03:29 +020018258static void alc663_mode3_inithook(struct hda_codec *codec)
18259{
18260 alc663_two_hp_m1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018261 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018262}
18263/* ***************** Mode4 ******************************/
18264static void alc663_mode4_unsol_event(struct hda_codec *codec,
18265 unsigned int res)
18266{
18267 switch (res >> 26) {
18268 case ALC880_HP_EVENT:
18269 alc663_21jd_two_speaker_automute(codec);
18270 break;
18271 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018272 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018273 break;
18274 }
18275}
18276
Kailang Yangebb83ee2009-12-17 12:23:00 +010018277#define alc663_mode4_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018278
Kailang Yangf1d4e282008-08-26 14:03:29 +020018279static void alc663_mode4_inithook(struct hda_codec *codec)
18280{
18281 alc663_21jd_two_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018282 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018283}
18284/* ***************** Mode5 ******************************/
18285static void alc663_mode5_unsol_event(struct hda_codec *codec,
18286 unsigned int res)
18287{
18288 switch (res >> 26) {
18289 case ALC880_HP_EVENT:
18290 alc663_15jd_two_speaker_automute(codec);
18291 break;
18292 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018293 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018294 break;
18295 }
18296}
18297
Kailang Yangebb83ee2009-12-17 12:23:00 +010018298#define alc663_mode5_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018299
Kailang Yangf1d4e282008-08-26 14:03:29 +020018300static void alc663_mode5_inithook(struct hda_codec *codec)
18301{
18302 alc663_15jd_two_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018303 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018304}
18305/* ***************** Mode6 ******************************/
18306static void alc663_mode6_unsol_event(struct hda_codec *codec,
18307 unsigned int res)
18308{
18309 switch (res >> 26) {
18310 case ALC880_HP_EVENT:
18311 alc663_two_hp_m2_speaker_automute(codec);
18312 break;
18313 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018314 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018315 break;
18316 }
18317}
18318
Kailang Yangebb83ee2009-12-17 12:23:00 +010018319#define alc663_mode6_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018320
Kailang Yangf1d4e282008-08-26 14:03:29 +020018321static void alc663_mode6_inithook(struct hda_codec *codec)
18322{
18323 alc663_two_hp_m2_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018324 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018325}
18326
Kailang Yangebb83ee2009-12-17 12:23:00 +010018327/* ***************** Mode7 ******************************/
18328static void alc663_mode7_unsol_event(struct hda_codec *codec,
18329 unsigned int res)
18330{
18331 switch (res >> 26) {
18332 case ALC880_HP_EVENT:
18333 alc663_two_hp_m7_speaker_automute(codec);
18334 break;
18335 case ALC880_MIC_EVENT:
18336 alc_mic_automute(codec);
18337 break;
18338 }
18339}
18340
18341#define alc663_mode7_setup alc663_mode1_setup
18342
18343static void alc663_mode7_inithook(struct hda_codec *codec)
18344{
18345 alc663_two_hp_m7_speaker_automute(codec);
18346 alc_mic_automute(codec);
18347}
18348
18349/* ***************** Mode8 ******************************/
18350static void alc663_mode8_unsol_event(struct hda_codec *codec,
18351 unsigned int res)
18352{
18353 switch (res >> 26) {
18354 case ALC880_HP_EVENT:
18355 alc663_two_hp_m8_speaker_automute(codec);
18356 break;
18357 case ALC880_MIC_EVENT:
18358 alc_mic_automute(codec);
18359 break;
18360 }
18361}
18362
18363#define alc663_mode8_setup alc663_m51va_setup
18364
18365static void alc663_mode8_inithook(struct hda_codec *codec)
18366{
18367 alc663_two_hp_m8_speaker_automute(codec);
18368 alc_mic_automute(codec);
18369}
18370
Kailang Yang6dda9f42008-05-27 12:05:31 +020018371static void alc663_g71v_hp_automute(struct hda_codec *codec)
18372{
18373 unsigned int present;
18374 unsigned char bits;
18375
Wu Fengguang864f92b2009-11-18 12:38:02 +080018376 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018377 bits = present ? HDA_AMP_MUTE : 0;
18378 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
18379 HDA_AMP_MUTE, bits);
18380 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
18381 HDA_AMP_MUTE, bits);
18382}
18383
18384static void alc663_g71v_front_automute(struct hda_codec *codec)
18385{
18386 unsigned int present;
18387 unsigned char bits;
18388
Wu Fengguang864f92b2009-11-18 12:38:02 +080018389 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018390 bits = present ? HDA_AMP_MUTE : 0;
18391 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
18392 HDA_AMP_MUTE, bits);
18393}
18394
18395static void alc663_g71v_unsol_event(struct hda_codec *codec,
18396 unsigned int res)
18397{
18398 switch (res >> 26) {
18399 case ALC880_HP_EVENT:
18400 alc663_g71v_hp_automute(codec);
18401 break;
18402 case ALC880_FRONT_EVENT:
18403 alc663_g71v_front_automute(codec);
18404 break;
18405 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018406 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018407 break;
18408 }
18409}
18410
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018411#define alc663_g71v_setup alc663_m51va_setup
18412
Kailang Yang6dda9f42008-05-27 12:05:31 +020018413static void alc663_g71v_inithook(struct hda_codec *codec)
18414{
18415 alc663_g71v_front_automute(codec);
18416 alc663_g71v_hp_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018417 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018418}
18419
18420static void alc663_g50v_unsol_event(struct hda_codec *codec,
18421 unsigned int res)
18422{
18423 switch (res >> 26) {
18424 case ALC880_HP_EVENT:
18425 alc663_m51va_speaker_automute(codec);
18426 break;
18427 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018428 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018429 break;
18430 }
18431}
18432
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018433#define alc663_g50v_setup alc663_m51va_setup
18434
Kailang Yang6dda9f42008-05-27 12:05:31 +020018435static void alc663_g50v_inithook(struct hda_codec *codec)
18436{
18437 alc663_m51va_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018438 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018439}
18440
Kailang Yangf1d4e282008-08-26 14:03:29 +020018441static struct snd_kcontrol_new alc662_ecs_mixer[] = {
18442 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020018443 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018444
18445 HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT),
18446 HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
18447 HDA_CODEC_MUTE("e-Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
18448
18449 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
18450 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
18451 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
18452 { } /* end */
18453};
18454
Chris Pockelé9541ba12009-05-12 08:08:53 +020018455static struct snd_kcontrol_new alc272_nc10_mixer[] = {
18456 /* Master Playback automatically created from Speaker and Headphone */
18457 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
18458 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
18459 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
18460 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
18461
18462 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
18463 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
18464 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
18465
18466 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
18467 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
18468 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
18469 { } /* end */
18470};
18471
Takashi Iwaicb53c622007-08-10 17:21:45 +020018472#ifdef CONFIG_SND_HDA_POWER_SAVE
18473#define alc662_loopbacks alc880_loopbacks
18474#endif
18475
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018476
Sasha Alexandrdef319f2009-06-16 16:00:15 -040018477/* pcm configuration: identical with ALC880 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018478#define alc662_pcm_analog_playback alc880_pcm_analog_playback
18479#define alc662_pcm_analog_capture alc880_pcm_analog_capture
18480#define alc662_pcm_digital_playback alc880_pcm_digital_playback
18481#define alc662_pcm_digital_capture alc880_pcm_digital_capture
18482
18483/*
18484 * configuration and preset
18485 */
18486static const char *alc662_models[ALC662_MODEL_LAST] = {
18487 [ALC662_3ST_2ch_DIG] = "3stack-dig",
18488 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
18489 [ALC662_3ST_6ch] = "3stack-6ch",
18490 [ALC662_5ST_DIG] = "6stack-dig",
18491 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020018492 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010018493 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangf1d4e282008-08-26 14:03:29 +020018494 [ALC662_ECS] = "ecs",
Kailang Yang6dda9f42008-05-27 12:05:31 +020018495 [ALC663_ASUS_M51VA] = "m51va",
18496 [ALC663_ASUS_G71V] = "g71v",
18497 [ALC663_ASUS_H13] = "h13",
18498 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangf1d4e282008-08-26 14:03:29 +020018499 [ALC663_ASUS_MODE1] = "asus-mode1",
18500 [ALC662_ASUS_MODE2] = "asus-mode2",
18501 [ALC663_ASUS_MODE3] = "asus-mode3",
18502 [ALC663_ASUS_MODE4] = "asus-mode4",
18503 [ALC663_ASUS_MODE5] = "asus-mode5",
18504 [ALC663_ASUS_MODE6] = "asus-mode6",
Kailang Yangebb83ee2009-12-17 12:23:00 +010018505 [ALC663_ASUS_MODE7] = "asus-mode7",
18506 [ALC663_ASUS_MODE8] = "asus-mode8",
Takashi Iwai01f2bd42009-05-11 08:12:43 +020018507 [ALC272_DELL] = "dell",
18508 [ALC272_DELL_ZM1] = "dell-zm1",
Chris Pockelé9541ba12009-05-12 08:08:53 +020018509 [ALC272_SAMSUNG_NC10] = "samsung-nc10",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018510 [ALC662_AUTO] = "auto",
18511};
18512
18513static struct snd_pci_quirk alc662_cfg_tbl[] = {
Takashi Iwaidea0a502009-02-09 17:14:52 +010018514 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
Kailang Yang622e84c2009-04-21 07:39:04 +020018515 SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
18516 SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018517 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
18518 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
Kailang Yangcec27c82010-02-04 14:18:18 +010018519 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018520 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
18521 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
18522 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
18523 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018524 SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC663_ASUS_MODE1),
18525 SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018526 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018527 SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC663_ASUS_MODE7),
18528 SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC663_ASUS_MODE7),
18529 SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC663_ASUS_MODE8),
18530 SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC663_ASUS_MODE3),
18531 SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018532 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018533 SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_ASUS_MODE2),
18534 SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018535 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
18536 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
18537 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
18538 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018539 SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020018540 SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3),
18541 SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA),
18542 SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018543 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
18544 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
18545 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
18546 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018547 SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018548 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
18549 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang6dda9f42008-05-27 12:05:31 +020018550 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018551 /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/
18552 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
18553 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020018554 SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1),
Kailang Yangcec27c82010-02-04 14:18:18 +010018555 SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020018556 SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1),
18557 SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018558 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
18559 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
18560 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018561 SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018562 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
18563 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020018564 SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018565 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
Kailang Yang80ffe862008-10-15 11:23:27 +020018566 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018567 /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/
18568 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
18569 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018570 SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018571 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
18572 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010018573 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020018574 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010018575 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018576 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
Herton Ronaldo Krzesinski95fe5f22008-09-26 23:48:45 -030018577 SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
18578 ALC662_3ST_6ch_DIG),
Takashi Iwai4dee8ba2010-01-13 17:20:08 +010018579 SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO),
Chris Pockelé9541ba12009-05-12 08:08:53 +020018580 SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
Herton Ronaldo Krzesinskicb559742008-09-26 23:47:45 -030018581 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
18582 ALC662_3ST_6ch_DIG),
Kailang Yang6227cdc2010-02-25 08:36:52 +010018583 SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13),
Vedran Miletic19c009a2008-09-29 20:29:25 +020018584 SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
Takashi Iwai5bd37292009-04-21 18:36:30 +020018585 SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018586 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Takashi Iwai238713d2008-10-05 10:57:39 +020018587 SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
Vedran Miletic19c009a2008-09-29 20:29:25 +020018588 ALC662_3ST_6ch_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018589 SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
18590 ALC663_ASUS_H13),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018591 {}
18592};
18593
18594static struct alc_config_preset alc662_presets[] = {
18595 [ALC662_3ST_2ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018596 .mixers = { alc662_3ST_2ch_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018597 .init_verbs = { alc662_init_verbs },
18598 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18599 .dac_nids = alc662_dac_nids,
18600 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018601 .dig_in_nid = ALC662_DIGIN_NID,
18602 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18603 .channel_mode = alc662_3ST_2ch_modes,
18604 .input_mux = &alc662_capture_source,
18605 },
18606 [ALC662_3ST_6ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018607 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018608 .init_verbs = { alc662_init_verbs },
18609 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18610 .dac_nids = alc662_dac_nids,
18611 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018612 .dig_in_nid = ALC662_DIGIN_NID,
18613 .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_3ST_6ch] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018619 .mixers = { alc662_3ST_6ch_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,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018623 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18624 .channel_mode = alc662_3ST_6ch_modes,
18625 .need_dac_fix = 1,
18626 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018627 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018628 [ALC662_5ST_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018629 .mixers = { alc662_base_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018630 .init_verbs = { alc662_init_verbs },
18631 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18632 .dac_nids = alc662_dac_nids,
18633 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018634 .dig_in_nid = ALC662_DIGIN_NID,
18635 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
18636 .channel_mode = alc662_5stack_modes,
18637 .input_mux = &alc662_capture_source,
18638 },
18639 [ALC662_LENOVO_101E] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018640 .mixers = { alc662_lenovo_101e_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018641 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
18642 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18643 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018644 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18645 .channel_mode = alc662_3ST_2ch_modes,
18646 .input_mux = &alc662_lenovo_101e_capture_source,
18647 .unsol_event = alc662_lenovo_101e_unsol_event,
18648 .init_hook = alc662_lenovo_101e_all_automute,
18649 },
Kailang Yang291702f2007-10-16 14:28:03 +020018650 [ALC662_ASUS_EEEPC_P701] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018651 .mixers = { alc662_eeepc_p701_mixer },
Kailang Yang291702f2007-10-16 14:28:03 +020018652 .init_verbs = { alc662_init_verbs,
18653 alc662_eeepc_sue_init_verbs },
18654 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18655 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020018656 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18657 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang291702f2007-10-16 14:28:03 +020018658 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018659 .setup = alc662_eeepc_setup,
Kailang Yang291702f2007-10-16 14:28:03 +020018660 .init_hook = alc662_eeepc_inithook,
18661 },
Kailang Yang8c427222008-01-10 13:03:59 +010018662 [ALC662_ASUS_EEEPC_EP20] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018663 .mixers = { alc662_eeepc_ep20_mixer,
Kailang Yang8c427222008-01-10 13:03:59 +010018664 alc662_chmode_mixer },
18665 .init_verbs = { alc662_init_verbs,
18666 alc662_eeepc_ep20_sue_init_verbs },
18667 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18668 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010018669 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18670 .channel_mode = alc662_3ST_6ch_modes,
18671 .input_mux = &alc662_lenovo_101e_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020018672 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018673 .setup = alc662_eeepc_ep20_setup,
Kailang Yang8c427222008-01-10 13:03:59 +010018674 .init_hook = alc662_eeepc_ep20_inithook,
18675 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018676 [ALC662_ECS] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018677 .mixers = { alc662_ecs_mixer },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018678 .init_verbs = { alc662_init_verbs,
18679 alc662_ecs_init_verbs },
18680 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18681 .dac_nids = alc662_dac_nids,
18682 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18683 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018684 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018685 .setup = alc662_eeepc_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018686 .init_hook = alc662_eeepc_inithook,
18687 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018688 [ALC663_ASUS_M51VA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018689 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018690 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
18691 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18692 .dac_nids = alc662_dac_nids,
18693 .dig_out_nid = ALC662_DIGOUT_NID,
18694 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18695 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018696 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018697 .setup = alc663_m51va_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018698 .init_hook = alc663_m51va_inithook,
18699 },
18700 [ALC663_ASUS_G71V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018701 .mixers = { alc663_g71v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018702 .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
18703 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18704 .dac_nids = alc662_dac_nids,
18705 .dig_out_nid = ALC662_DIGOUT_NID,
18706 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18707 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018708 .unsol_event = alc663_g71v_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018709 .setup = alc663_g71v_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018710 .init_hook = alc663_g71v_inithook,
18711 },
18712 [ALC663_ASUS_H13] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018713 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018714 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
18715 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18716 .dac_nids = alc662_dac_nids,
18717 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18718 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018719 .unsol_event = alc663_m51va_unsol_event,
18720 .init_hook = alc663_m51va_inithook,
18721 },
18722 [ALC663_ASUS_G50V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018723 .mixers = { alc663_g50v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018724 .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
18725 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18726 .dac_nids = alc662_dac_nids,
18727 .dig_out_nid = ALC662_DIGOUT_NID,
18728 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18729 .channel_mode = alc662_3ST_6ch_modes,
18730 .input_mux = &alc663_capture_source,
18731 .unsol_event = alc663_g50v_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018732 .setup = alc663_g50v_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018733 .init_hook = alc663_g50v_inithook,
18734 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018735 [ALC663_ASUS_MODE1] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018736 .mixers = { alc663_m51va_mixer },
18737 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018738 .init_verbs = { alc662_init_verbs,
18739 alc663_21jd_amic_init_verbs },
18740 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18741 .hp_nid = 0x03,
18742 .dac_nids = alc662_dac_nids,
18743 .dig_out_nid = ALC662_DIGOUT_NID,
18744 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18745 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018746 .unsol_event = alc663_mode1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018747 .setup = alc663_mode1_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018748 .init_hook = alc663_mode1_inithook,
18749 },
18750 [ALC662_ASUS_MODE2] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018751 .mixers = { alc662_1bjd_mixer },
18752 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018753 .init_verbs = { alc662_init_verbs,
18754 alc662_1bjd_amic_init_verbs },
18755 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18756 .dac_nids = alc662_dac_nids,
18757 .dig_out_nid = ALC662_DIGOUT_NID,
18758 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18759 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018760 .unsol_event = alc662_mode2_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018761 .setup = alc662_mode2_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018762 .init_hook = alc662_mode2_inithook,
18763 },
18764 [ALC663_ASUS_MODE3] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018765 .mixers = { alc663_two_hp_m1_mixer },
18766 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018767 .init_verbs = { alc662_init_verbs,
18768 alc663_two_hp_amic_m1_init_verbs },
18769 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18770 .hp_nid = 0x03,
18771 .dac_nids = alc662_dac_nids,
18772 .dig_out_nid = ALC662_DIGOUT_NID,
18773 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18774 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018775 .unsol_event = alc663_mode3_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018776 .setup = alc663_mode3_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018777 .init_hook = alc663_mode3_inithook,
18778 },
18779 [ALC663_ASUS_MODE4] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018780 .mixers = { alc663_asus_21jd_clfe_mixer },
18781 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018782 .init_verbs = { alc662_init_verbs,
18783 alc663_21jd_amic_init_verbs},
18784 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18785 .hp_nid = 0x03,
18786 .dac_nids = alc662_dac_nids,
18787 .dig_out_nid = ALC662_DIGOUT_NID,
18788 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18789 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018790 .unsol_event = alc663_mode4_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018791 .setup = alc663_mode4_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018792 .init_hook = alc663_mode4_inithook,
18793 },
18794 [ALC663_ASUS_MODE5] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018795 .mixers = { alc663_asus_15jd_clfe_mixer },
18796 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018797 .init_verbs = { alc662_init_verbs,
18798 alc663_15jd_amic_init_verbs },
18799 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18800 .hp_nid = 0x03,
18801 .dac_nids = alc662_dac_nids,
18802 .dig_out_nid = ALC662_DIGOUT_NID,
18803 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18804 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018805 .unsol_event = alc663_mode5_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018806 .setup = alc663_mode5_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018807 .init_hook = alc663_mode5_inithook,
18808 },
18809 [ALC663_ASUS_MODE6] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018810 .mixers = { alc663_two_hp_m2_mixer },
18811 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018812 .init_verbs = { alc662_init_verbs,
18813 alc663_two_hp_amic_m2_init_verbs },
18814 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18815 .hp_nid = 0x03,
18816 .dac_nids = alc662_dac_nids,
18817 .dig_out_nid = ALC662_DIGOUT_NID,
18818 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18819 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018820 .unsol_event = alc663_mode6_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018821 .setup = alc663_mode6_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018822 .init_hook = alc663_mode6_inithook,
18823 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010018824 [ALC663_ASUS_MODE7] = {
18825 .mixers = { alc663_mode7_mixer },
18826 .cap_mixer = alc662_auto_capture_mixer,
18827 .init_verbs = { alc662_init_verbs,
18828 alc663_mode7_init_verbs },
18829 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18830 .hp_nid = 0x03,
18831 .dac_nids = alc662_dac_nids,
18832 .dig_out_nid = ALC662_DIGOUT_NID,
18833 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18834 .channel_mode = alc662_3ST_2ch_modes,
18835 .unsol_event = alc663_mode7_unsol_event,
18836 .setup = alc663_mode7_setup,
18837 .init_hook = alc663_mode7_inithook,
18838 },
18839 [ALC663_ASUS_MODE8] = {
18840 .mixers = { alc663_mode8_mixer },
18841 .cap_mixer = alc662_auto_capture_mixer,
18842 .init_verbs = { alc662_init_verbs,
18843 alc663_mode8_init_verbs },
18844 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18845 .hp_nid = 0x03,
18846 .dac_nids = alc662_dac_nids,
18847 .dig_out_nid = ALC662_DIGOUT_NID,
18848 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18849 .channel_mode = alc662_3ST_2ch_modes,
18850 .unsol_event = alc663_mode8_unsol_event,
18851 .setup = alc663_mode8_setup,
18852 .init_hook = alc663_mode8_inithook,
18853 },
Kailang Yang622e84c2009-04-21 07:39:04 +020018854 [ALC272_DELL] = {
18855 .mixers = { alc663_m51va_mixer },
18856 .cap_mixer = alc272_auto_capture_mixer,
18857 .init_verbs = { alc662_init_verbs, alc272_dell_init_verbs },
18858 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18859 .dac_nids = alc662_dac_nids,
18860 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18861 .adc_nids = alc272_adc_nids,
18862 .num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
18863 .capsrc_nids = alc272_capsrc_nids,
18864 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang622e84c2009-04-21 07:39:04 +020018865 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018866 .setup = alc663_m51va_setup,
Kailang Yang622e84c2009-04-21 07:39:04 +020018867 .init_hook = alc663_m51va_inithook,
18868 },
18869 [ALC272_DELL_ZM1] = {
18870 .mixers = { alc663_m51va_mixer },
18871 .cap_mixer = alc662_auto_capture_mixer,
18872 .init_verbs = { alc662_init_verbs, alc272_dell_zm1_init_verbs },
18873 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18874 .dac_nids = alc662_dac_nids,
18875 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18876 .adc_nids = alc662_adc_nids,
Takashi Iwaib59bdf32009-08-11 09:47:30 +020018877 .num_adc_nids = 1,
Kailang Yang622e84c2009-04-21 07:39:04 +020018878 .capsrc_nids = alc662_capsrc_nids,
18879 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang622e84c2009-04-21 07:39:04 +020018880 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018881 .setup = alc663_m51va_setup,
Kailang Yang622e84c2009-04-21 07:39:04 +020018882 .init_hook = alc663_m51va_inithook,
18883 },
Chris Pockelé9541ba12009-05-12 08:08:53 +020018884 [ALC272_SAMSUNG_NC10] = {
18885 .mixers = { alc272_nc10_mixer },
18886 .init_verbs = { alc662_init_verbs,
18887 alc663_21jd_amic_init_verbs },
18888 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18889 .dac_nids = alc272_dac_nids,
18890 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18891 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018892 /*.input_mux = &alc272_nc10_capture_source,*/
Chris Pockelé9541ba12009-05-12 08:08:53 +020018893 .unsol_event = alc663_mode4_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018894 .setup = alc663_mode4_setup,
Chris Pockelé9541ba12009-05-12 08:08:53 +020018895 .init_hook = alc663_mode4_inithook,
18896 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018897};
18898
18899
18900/*
18901 * BIOS auto configuration
18902 */
18903
Takashi Iwai7085ec12009-10-02 09:03:58 +020018904/* convert from MIX nid to DAC */
18905static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid)
18906{
18907 if (nid == 0x0f)
18908 return 0x02;
18909 else if (nid >= 0x0c && nid <= 0x0e)
18910 return nid - 0x0c + 0x02;
18911 else
18912 return 0;
18913}
18914
18915/* get MIX nid connected to the given pin targeted to DAC */
18916static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
18917 hda_nid_t dac)
18918{
18919 hda_nid_t mix[4];
18920 int i, num;
18921
18922 num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
18923 for (i = 0; i < num; i++) {
18924 if (alc662_mix_to_dac(mix[i]) == dac)
18925 return mix[i];
18926 }
18927 return 0;
18928}
18929
18930/* look for an empty DAC slot */
18931static hda_nid_t alc662_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
18932{
18933 struct alc_spec *spec = codec->spec;
18934 hda_nid_t srcs[5];
18935 int i, j, num;
18936
18937 num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
18938 if (num < 0)
18939 return 0;
18940 for (i = 0; i < num; i++) {
18941 hda_nid_t nid = alc662_mix_to_dac(srcs[i]);
18942 if (!nid)
18943 continue;
18944 for (j = 0; j < spec->multiout.num_dacs; j++)
18945 if (spec->multiout.dac_nids[j] == nid)
18946 break;
18947 if (j >= spec->multiout.num_dacs)
18948 return nid;
18949 }
18950 return 0;
18951}
18952
18953/* fill in the dac_nids table from the parsed pin configuration */
18954static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
18955 const struct auto_pin_cfg *cfg)
18956{
18957 struct alc_spec *spec = codec->spec;
18958 int i;
18959 hda_nid_t dac;
18960
18961 spec->multiout.dac_nids = spec->private_dac_nids;
18962 for (i = 0; i < cfg->line_outs; i++) {
18963 dac = alc662_look_for_dac(codec, cfg->line_out_pins[i]);
18964 if (!dac)
18965 continue;
18966 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
18967 }
18968 return 0;
18969}
18970
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018971static inline int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018972 hda_nid_t nid, unsigned int chs)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018973{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018974 return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018975 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
18976}
18977
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018978static inline int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018979 hda_nid_t nid, unsigned int chs)
18980{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018981 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018982 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
18983}
18984
18985#define alc662_add_stereo_vol(spec, pfx, nid) \
18986 alc662_add_vol_ctl(spec, pfx, nid, 3)
18987#define alc662_add_stereo_sw(spec, pfx, nid) \
18988 alc662_add_sw_ctl(spec, pfx, nid, 3)
18989
18990/* add playback controls from the parsed DAC table */
18991static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
18992 const struct auto_pin_cfg *cfg)
18993{
18994 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018995 static const char *chname[4] = {
18996 "Front", "Surround", NULL /*CLFE*/, "Side"
18997 };
Takashi Iwai7085ec12009-10-02 09:03:58 +020018998 hda_nid_t nid, mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018999 int i, err;
19000
19001 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020019002 nid = spec->multiout.dac_nids[i];
19003 if (!nid)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019004 continue;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019005 mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid);
19006 if (!mix)
19007 continue;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019008 if (i == 2) {
19009 /* Center/LFE */
Takashi Iwai7085ec12009-10-02 09:03:58 +020019010 err = alc662_add_vol_ctl(spec, "Center", nid, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019011 if (err < 0)
19012 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019013 err = alc662_add_vol_ctl(spec, "LFE", nid, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019014 if (err < 0)
19015 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019016 err = alc662_add_sw_ctl(spec, "Center", mix, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019017 if (err < 0)
19018 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019019 err = alc662_add_sw_ctl(spec, "LFE", mix, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019020 if (err < 0)
19021 return err;
19022 } else {
Takashi Iwai0d884cb2009-08-25 16:14:35 +020019023 const char *pfx;
19024 if (cfg->line_outs == 1 &&
19025 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020019026 if (cfg->hp_outs)
Takashi Iwai0d884cb2009-08-25 16:14:35 +020019027 pfx = "Speaker";
19028 else
19029 pfx = "PCM";
19030 } else
19031 pfx = chname[i];
Takashi Iwai7085ec12009-10-02 09:03:58 +020019032 err = alc662_add_vol_ctl(spec, pfx, nid, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019033 if (err < 0)
19034 return err;
Takashi Iwai0d884cb2009-08-25 16:14:35 +020019035 if (cfg->line_outs == 1 &&
19036 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
19037 pfx = "Speaker";
Takashi Iwai7085ec12009-10-02 09:03:58 +020019038 err = alc662_add_sw_ctl(spec, pfx, mix, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019039 if (err < 0)
19040 return err;
19041 }
19042 }
19043 return 0;
19044}
19045
19046/* add playback controls for speaker and HP outputs */
Takashi Iwai7085ec12009-10-02 09:03:58 +020019047/* return DAC nid if any new DAC is assigned */
19048static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019049 const char *pfx)
19050{
Takashi Iwai7085ec12009-10-02 09:03:58 +020019051 struct alc_spec *spec = codec->spec;
19052 hda_nid_t nid, mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019053 int err;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019054
19055 if (!pin)
19056 return 0;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019057 nid = alc662_look_for_dac(codec, pin);
19058 if (!nid) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020019059 /* the corresponding DAC is already occupied */
19060 if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
19061 return 0; /* no way */
19062 /* create a switch only */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020019063 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019064 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
19065 }
19066
19067 mix = alc662_dac_to_mix(codec, pin, nid);
19068 if (!mix)
19069 return 0;
19070 err = alc662_add_vol_ctl(spec, pfx, nid, 3);
19071 if (err < 0)
Takashi Iwai24fb9172008-09-02 14:48:20 +020019072 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019073 err = alc662_add_sw_ctl(spec, pfx, mix, 3);
19074 if (err < 0)
19075 return err;
19076 return nid;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019077}
19078
19079/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020019080#define alc662_auto_create_input_ctls \
Takashi Iwai4b7348a2009-10-14 18:25:23 +020019081 alc882_auto_create_input_ctls
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019082
19083static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
19084 hda_nid_t nid, int pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019085 hda_nid_t dac)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019086{
Takashi Iwai7085ec12009-10-02 09:03:58 +020019087 int i, num;
Takashi Iwaice503f32010-07-30 10:37:29 +020019088 hda_nid_t srcs[HDA_MAX_CONNECTIONS];
Takashi Iwai7085ec12009-10-02 09:03:58 +020019089
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019090 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019091 /* need the manual connection? */
Takashi Iwai7085ec12009-10-02 09:03:58 +020019092 num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
19093 if (num <= 1)
19094 return;
19095 for (i = 0; i < num; i++) {
19096 if (alc662_mix_to_dac(srcs[i]) != dac)
19097 continue;
19098 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
19099 return;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019100 }
19101}
19102
19103static void alc662_auto_init_multi_out(struct hda_codec *codec)
19104{
19105 struct alc_spec *spec = codec->spec;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019106 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019107 int i;
19108
19109 for (i = 0; i <= HDA_SIDE; i++) {
19110 hda_nid_t nid = spec->autocfg.line_out_pins[i];
19111 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020019112 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019113 spec->multiout.dac_nids[i]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019114 }
19115}
19116
19117static void alc662_auto_init_hp_out(struct hda_codec *codec)
19118{
19119 struct alc_spec *spec = codec->spec;
19120 hda_nid_t pin;
19121
19122 pin = spec->autocfg.hp_pins[0];
Takashi Iwai7085ec12009-10-02 09:03:58 +020019123 if (pin)
19124 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP,
19125 spec->multiout.hp_nid);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019126 pin = spec->autocfg.speaker_pins[0];
19127 if (pin)
Takashi Iwai7085ec12009-10-02 09:03:58 +020019128 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT,
19129 spec->multiout.extra_out_nid[0]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019130}
19131
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019132#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
19133
19134static void alc662_auto_init_analog_input(struct hda_codec *codec)
19135{
19136 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019137 struct auto_pin_cfg *cfg = &spec->autocfg;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019138 int i;
19139
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019140 for (i = 0; i < cfg->num_inputs; i++) {
19141 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +020019142 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai30ea0982010-09-16 18:47:56 +020019143 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwai52ca15b2009-03-23 12:51:55 +010019144 if (nid != ALC662_PIN_CD_NID &&
Takashi Iwaie82c0252009-03-23 15:17:38 +010019145 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019146 snd_hda_codec_write(codec, nid, 0,
19147 AC_VERB_SET_AMP_GAIN_MUTE,
19148 AMP_OUT_MUTE);
19149 }
19150 }
19151}
19152
Takashi Iwaif511b012008-08-15 16:46:42 +020019153#define alc662_auto_init_input_src alc882_auto_init_input_src
19154
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019155static int alc662_parse_auto_config(struct hda_codec *codec)
19156{
19157 struct alc_spec *spec = codec->spec;
19158 int err;
19159 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
19160
19161 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
19162 alc662_ignore);
19163 if (err < 0)
19164 return err;
19165 if (!spec->autocfg.line_outs)
19166 return 0; /* can't find valid BIOS pin config */
19167
Takashi Iwai7085ec12009-10-02 09:03:58 +020019168 err = alc662_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019169 if (err < 0)
19170 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019171 err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019172 if (err < 0)
19173 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019174 err = alc662_auto_create_extra_out(codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019175 spec->autocfg.speaker_pins[0],
19176 "Speaker");
19177 if (err < 0)
19178 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019179 if (err)
19180 spec->multiout.extra_out_nid[0] = err;
19181 err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019182 "Headphone");
19183 if (err < 0)
19184 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019185 if (err)
19186 spec->multiout.hp_nid = err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020019187 err = alc662_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019188 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019189 return err;
19190
19191 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
19192
Takashi Iwai757899a2010-07-30 10:48:14 +020019193 alc_auto_parse_digital(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019194
Takashi Iwai603c4012008-07-30 15:01:44 +020019195 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010019196 add_mixer(spec, spec->kctls.list);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019197
19198 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020019199 spec->input_mux = &spec->private_imux[0];
Kailang Yangea1fb292008-08-26 12:58:38 +020019200
Kailang Yangcec27c82010-02-04 14:18:18 +010019201 add_verb(spec, alc662_init_verbs);
19202 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019203 codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
Kailang Yangcec27c82010-02-04 14:18:18 +010019204 add_verb(spec, alc663_init_verbs);
19205
19206 if (codec->vendor_id == 0x10ec0272)
19207 add_verb(spec, alc272_init_verbs);
Takashi Iwaiee979a142008-09-02 15:42:20 +020019208
19209 err = alc_auto_add_mic_boost(codec);
19210 if (err < 0)
19211 return err;
19212
Kailang Yang6227cdc2010-02-25 08:36:52 +010019213 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
19214 codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
19215 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0x21);
19216 else
19217 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020019218
Takashi Iwai8c872862007-06-19 12:11:16 +020019219 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019220}
19221
19222/* additional initialization for auto-configuration model */
19223static void alc662_auto_init(struct hda_codec *codec)
19224{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019225 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019226 alc662_auto_init_multi_out(codec);
19227 alc662_auto_init_hp_out(codec);
19228 alc662_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020019229 alc662_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020019230 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019231 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020019232 alc_inithook(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019233}
19234
David Henningsson6cb3b702010-09-09 08:51:44 +020019235enum {
Daniel T Chen2df03512010-10-10 22:39:28 -040019236 ALC662_FIXUP_ASPIRE,
David Henningsson6cb3b702010-09-09 08:51:44 +020019237 ALC662_FIXUP_IDEAPAD,
19238};
19239
19240static const struct alc_fixup alc662_fixups[] = {
Daniel T Chen2df03512010-10-10 22:39:28 -040019241 [ALC662_FIXUP_ASPIRE] = {
19242 .pins = (const struct alc_pincfg[]) {
19243 { 0x15, 0x99130112 }, /* subwoofer */
19244 { }
19245 }
19246 },
David Henningsson6cb3b702010-09-09 08:51:44 +020019247 [ALC662_FIXUP_IDEAPAD] = {
19248 .pins = (const struct alc_pincfg[]) {
19249 { 0x17, 0x99130112 }, /* subwoofer */
19250 { }
19251 }
19252 },
19253};
19254
19255static struct snd_pci_quirk alc662_fixup_tbl[] = {
Daniel T Chen2df03512010-10-10 22:39:28 -040019256 SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
Valentine Sinitsynd4118582010-10-01 22:24:08 +060019257 SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
David Henningsson6cb3b702010-09-09 08:51:44 +020019258 SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
19259 {}
19260};
19261
19262
19263
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019264static int patch_alc662(struct hda_codec *codec)
19265{
19266 struct alc_spec *spec;
19267 int err, board_config;
19268
19269 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
19270 if (!spec)
19271 return -ENOMEM;
19272
19273 codec->spec = spec;
19274
Kailang Yangda00c242010-03-19 11:23:45 +010019275 alc_auto_parse_customize_define(codec);
19276
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020019277 alc_fix_pll_init(codec, 0x20, 0x04, 15);
19278
Kailang Yangc027ddc2010-03-19 11:33:06 +010019279 if (alc_read_coef_idx(codec, 0) == 0x8020)
19280 alc_codec_rename(codec, "ALC661");
19281 else if ((alc_read_coef_idx(codec, 0) & (1 << 14)) &&
19282 codec->bus->pci->subsystem_vendor == 0x1025 &&
19283 spec->cdefine.platform_type == 1)
19284 alc_codec_rename(codec, "ALC272X");
Kailang Yang274693f2009-12-03 10:07:50 +010019285
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019286 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
19287 alc662_models,
19288 alc662_cfg_tbl);
19289 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020019290 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
19291 codec->chip_name);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019292 board_config = ALC662_AUTO;
19293 }
19294
19295 if (board_config == ALC662_AUTO) {
David Henningsson6cb3b702010-09-09 08:51:44 +020019296 alc_pick_fixup(codec, alc662_fixup_tbl, alc662_fixups, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019297 /* automatic parse from the BIOS config */
19298 err = alc662_parse_auto_config(codec);
19299 if (err < 0) {
19300 alc_free(codec);
19301 return err;
Takashi Iwai8c872862007-06-19 12:11:16 +020019302 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019303 printk(KERN_INFO
19304 "hda_codec: Cannot set up configuration "
19305 "from BIOS. Using base mode...\n");
19306 board_config = ALC662_3ST_2ch_DIG;
19307 }
19308 }
19309
Takashi Iwaidc1eae22010-07-29 15:30:02 +020019310 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020019311 err = snd_hda_attach_beep_device(codec, 0x1);
19312 if (err < 0) {
19313 alc_free(codec);
19314 return err;
19315 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090019316 }
19317
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019318 if (board_config != ALC662_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020019319 setup_preset(codec, &alc662_presets[board_config]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019320
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019321 spec->stream_analog_playback = &alc662_pcm_analog_playback;
19322 spec->stream_analog_capture = &alc662_pcm_analog_capture;
19323
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019324 spec->stream_digital_playback = &alc662_pcm_digital_playback;
19325 spec->stream_digital_capture = &alc662_pcm_digital_capture;
19326
Takashi Iwaidd704692009-08-11 08:45:11 +020019327 if (!spec->adc_nids) {
19328 spec->adc_nids = alc662_adc_nids;
19329 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
19330 }
19331 if (!spec->capsrc_nids)
19332 spec->capsrc_nids = alc662_capsrc_nids;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019333
Takashi Iwaif9e336f2008-10-31 16:37:07 +010019334 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020019335 set_capture_mixer(codec);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010019336
Takashi Iwaidc1eae22010-07-29 15:30:02 +020019337 if (has_cdefine_beep(codec)) {
Kailang Yangda00c242010-03-19 11:23:45 +010019338 switch (codec->vendor_id) {
19339 case 0x10ec0662:
19340 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
19341 break;
19342 case 0x10ec0272:
19343 case 0x10ec0663:
19344 case 0x10ec0665:
19345 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
19346 break;
19347 case 0x10ec0273:
19348 set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
19349 break;
19350 }
Kailang Yangcec27c82010-02-04 14:18:18 +010019351 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010019352 spec->vmaster_nid = 0x02;
19353
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019354 codec->patch_ops = alc_patch_ops;
David Henningsson6cb3b702010-09-09 08:51:44 +020019355 if (board_config == ALC662_AUTO) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019356 spec->init_hook = alc662_auto_init;
David Henningsson6cb3b702010-09-09 08:51:44 +020019357 alc_pick_fixup(codec, alc662_fixup_tbl, alc662_fixups, 0);
19358 }
19359
Takashi Iwaicb53c622007-08-10 17:21:45 +020019360#ifdef CONFIG_SND_HDA_POWER_SAVE
19361 if (!spec->loopback.amplist)
19362 spec->loopback.amplist = alc662_loopbacks;
19363#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019364
19365 return 0;
19366}
19367
Kailang Yang274693f2009-12-03 10:07:50 +010019368static int patch_alc888(struct hda_codec *codec)
19369{
19370 if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){
19371 kfree(codec->chip_name);
19372 codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010019373 if (!codec->chip_name) {
19374 alc_free(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010019375 return -ENOMEM;
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010019376 }
19377 return patch_alc662(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010019378 }
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010019379 return patch_alc882(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010019380}
19381
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019382/*
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019383 * ALC680 support
19384 */
Kailang Yangc69aefa2010-08-17 10:39:22 +020019385#define ALC680_DIGIN_NID ALC880_DIGIN_NID
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019386#define ALC680_DIGOUT_NID ALC880_DIGOUT_NID
19387#define alc680_modes alc260_modes
19388
19389static hda_nid_t alc680_dac_nids[3] = {
19390 /* Lout1, Lout2, hp */
19391 0x02, 0x03, 0x04
19392};
19393
19394static hda_nid_t alc680_adc_nids[3] = {
19395 /* ADC0-2 */
19396 /* DMIC, MIC, Line-in*/
19397 0x07, 0x08, 0x09
19398};
19399
Kailang Yangc69aefa2010-08-17 10:39:22 +020019400/*
19401 * Analog capture ADC cgange
19402 */
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019403static void alc680_rec_autoswitch(struct hda_codec *codec)
19404{
19405 struct alc_spec *spec = codec->spec;
19406 struct auto_pin_cfg *cfg = &spec->autocfg;
19407 int pin_found = 0;
19408 int type_found = AUTO_PIN_LAST;
19409 hda_nid_t nid;
19410 int i;
19411
19412 for (i = 0; i < cfg->num_inputs; i++) {
19413 nid = cfg->inputs[i].pin;
19414 if (!(snd_hda_query_pin_caps(codec, nid) &
19415 AC_PINCAP_PRES_DETECT))
19416 continue;
19417 if (snd_hda_jack_detect(codec, nid)) {
19418 if (cfg->inputs[i].type < type_found) {
19419 type_found = cfg->inputs[i].type;
19420 pin_found = nid;
19421 }
19422 }
19423 }
19424
19425 nid = 0x07;
19426 if (pin_found)
19427 snd_hda_get_connections(codec, pin_found, &nid, 1);
19428
19429 if (nid != spec->cur_adc)
19430 __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
19431 spec->cur_adc = nid;
19432 snd_hda_codec_setup_stream(codec, nid, spec->cur_adc_stream_tag, 0,
19433 spec->cur_adc_format);
19434}
19435
Kailang Yangc69aefa2010-08-17 10:39:22 +020019436static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
19437 struct hda_codec *codec,
19438 unsigned int stream_tag,
19439 unsigned int format,
19440 struct snd_pcm_substream *substream)
19441{
19442 struct alc_spec *spec = codec->spec;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019443
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019444 spec->cur_adc = 0x07;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019445 spec->cur_adc_stream_tag = stream_tag;
19446 spec->cur_adc_format = format;
19447
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019448 alc680_rec_autoswitch(codec);
Kailang Yangc69aefa2010-08-17 10:39:22 +020019449 return 0;
19450}
19451
19452static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
19453 struct hda_codec *codec,
19454 struct snd_pcm_substream *substream)
19455{
19456 snd_hda_codec_cleanup_stream(codec, 0x07);
19457 snd_hda_codec_cleanup_stream(codec, 0x08);
19458 snd_hda_codec_cleanup_stream(codec, 0x09);
19459 return 0;
19460}
19461
19462static struct hda_pcm_stream alc680_pcm_analog_auto_capture = {
19463 .substreams = 1, /* can be overridden */
19464 .channels_min = 2,
19465 .channels_max = 2,
19466 /* NID is set in alc_build_pcms */
19467 .ops = {
19468 .prepare = alc680_capture_pcm_prepare,
19469 .cleanup = alc680_capture_pcm_cleanup
19470 },
19471};
19472
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019473static struct snd_kcontrol_new alc680_base_mixer[] = {
19474 /* output mixer control */
19475 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
19476 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
19477 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT),
19478 HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yangc69aefa2010-08-17 10:39:22 +020019479 HDA_CODEC_VOLUME("Int Mic Boost", 0x12, 0, HDA_INPUT),
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019480 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangc69aefa2010-08-17 10:39:22 +020019481 HDA_CODEC_VOLUME("Line In Boost", 0x19, 0, HDA_INPUT),
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019482 { }
19483};
19484
Kailang Yangc69aefa2010-08-17 10:39:22 +020019485static struct hda_bind_ctls alc680_bind_cap_vol = {
19486 .ops = &snd_hda_bind_vol,
19487 .values = {
19488 HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
19489 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
19490 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
19491 0
19492 },
19493};
19494
19495static struct hda_bind_ctls alc680_bind_cap_switch = {
19496 .ops = &snd_hda_bind_sw,
19497 .values = {
19498 HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
19499 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
19500 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
19501 0
19502 },
19503};
19504
19505static struct snd_kcontrol_new alc680_master_capture_mixer[] = {
19506 HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol),
19507 HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch),
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019508 { } /* end */
19509};
19510
19511/*
19512 * generic initialization of ADC, input mixers and output mixers
19513 */
19514static struct hda_verb alc680_init_verbs[] = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019515 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
19516 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
19517 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019518
Kailang Yangc69aefa2010-08-17 10:39:22 +020019519 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
19520 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
19521 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
19522 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
19523 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
19524 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019525
19526 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19527 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19528 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19529 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19530 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yangc69aefa2010-08-17 10:39:22 +020019531
19532 {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
19533 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019534 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Kailang Yangc69aefa2010-08-17 10:39:22 +020019535
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019536 { }
19537};
19538
Kailang Yangc69aefa2010-08-17 10:39:22 +020019539/* toggle speaker-output according to the hp-jack state */
19540static void alc680_base_setup(struct hda_codec *codec)
19541{
19542 struct alc_spec *spec = codec->spec;
19543
19544 spec->autocfg.hp_pins[0] = 0x16;
19545 spec->autocfg.speaker_pins[0] = 0x14;
19546 spec->autocfg.speaker_pins[1] = 0x15;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019547 spec->autocfg.num_inputs = 2;
19548 spec->autocfg.inputs[0].pin = 0x18;
19549 spec->autocfg.inputs[0].type = AUTO_PIN_MIC;
19550 spec->autocfg.inputs[1].pin = 0x19;
Takashi Iwai86e29592010-09-09 14:50:17 +020019551 spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019552}
19553
19554static void alc680_unsol_event(struct hda_codec *codec,
19555 unsigned int res)
19556{
19557 if ((res >> 26) == ALC880_HP_EVENT)
19558 alc_automute_amp(codec);
19559 if ((res >> 26) == ALC880_MIC_EVENT)
19560 alc680_rec_autoswitch(codec);
19561}
19562
19563static void alc680_inithook(struct hda_codec *codec)
19564{
19565 alc_automute_amp(codec);
19566 alc680_rec_autoswitch(codec);
19567}
19568
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019569/* create input playback/capture controls for the given pin */
19570static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
19571 const char *ctlname, int idx)
19572{
19573 hda_nid_t dac;
19574 int err;
19575
19576 switch (nid) {
19577 case 0x14:
19578 dac = 0x02;
19579 break;
19580 case 0x15:
19581 dac = 0x03;
19582 break;
19583 case 0x16:
19584 dac = 0x04;
19585 break;
19586 default:
19587 return 0;
19588 }
19589 if (spec->multiout.dac_nids[0] != dac &&
19590 spec->multiout.dac_nids[1] != dac) {
19591 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
19592 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
19593 HDA_OUTPUT));
19594 if (err < 0)
19595 return err;
19596
19597 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
19598 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
19599
19600 if (err < 0)
19601 return err;
19602 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
19603 }
19604
19605 return 0;
19606}
19607
19608/* add playback controls from the parsed DAC table */
19609static int alc680_auto_create_multi_out_ctls(struct alc_spec *spec,
19610 const struct auto_pin_cfg *cfg)
19611{
19612 hda_nid_t nid;
19613 int err;
19614
19615 spec->multiout.dac_nids = spec->private_dac_nids;
19616
19617 nid = cfg->line_out_pins[0];
19618 if (nid) {
19619 const char *name;
19620 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
19621 name = "Speaker";
19622 else
19623 name = "Front";
19624 err = alc680_new_analog_output(spec, nid, name, 0);
19625 if (err < 0)
19626 return err;
19627 }
19628
19629 nid = cfg->speaker_pins[0];
19630 if (nid) {
19631 err = alc680_new_analog_output(spec, nid, "Speaker", 0);
19632 if (err < 0)
19633 return err;
19634 }
19635 nid = cfg->hp_pins[0];
19636 if (nid) {
19637 err = alc680_new_analog_output(spec, nid, "Headphone", 0);
19638 if (err < 0)
19639 return err;
19640 }
19641
19642 return 0;
19643}
19644
19645static void alc680_auto_set_output_and_unmute(struct hda_codec *codec,
19646 hda_nid_t nid, int pin_type)
19647{
19648 alc_set_pin_output(codec, nid, pin_type);
19649}
19650
19651static void alc680_auto_init_multi_out(struct hda_codec *codec)
19652{
19653 struct alc_spec *spec = codec->spec;
19654 hda_nid_t nid = spec->autocfg.line_out_pins[0];
19655 if (nid) {
19656 int pin_type = get_pin_type(spec->autocfg.line_out_type);
19657 alc680_auto_set_output_and_unmute(codec, nid, pin_type);
19658 }
19659}
19660
19661static void alc680_auto_init_hp_out(struct hda_codec *codec)
19662{
19663 struct alc_spec *spec = codec->spec;
19664 hda_nid_t pin;
19665
19666 pin = spec->autocfg.hp_pins[0];
19667 if (pin)
19668 alc680_auto_set_output_and_unmute(codec, pin, PIN_HP);
19669 pin = spec->autocfg.speaker_pins[0];
19670 if (pin)
19671 alc680_auto_set_output_and_unmute(codec, pin, PIN_OUT);
19672}
19673
19674/* pcm configuration: identical with ALC880 */
19675#define alc680_pcm_analog_playback alc880_pcm_analog_playback
19676#define alc680_pcm_analog_capture alc880_pcm_analog_capture
19677#define alc680_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
19678#define alc680_pcm_digital_playback alc880_pcm_digital_playback
Kailang Yangc69aefa2010-08-17 10:39:22 +020019679#define alc680_pcm_digital_capture alc880_pcm_digital_capture
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019680
19681/*
19682 * BIOS auto configuration
19683 */
19684static int alc680_parse_auto_config(struct hda_codec *codec)
19685{
19686 struct alc_spec *spec = codec->spec;
19687 int err;
19688 static hda_nid_t alc680_ignore[] = { 0 };
19689
19690 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
19691 alc680_ignore);
19692 if (err < 0)
19693 return err;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019694
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019695 if (!spec->autocfg.line_outs) {
19696 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
19697 spec->multiout.max_channels = 2;
19698 spec->no_analog = 1;
19699 goto dig_only;
19700 }
19701 return 0; /* can't find valid BIOS pin config */
19702 }
19703 err = alc680_auto_create_multi_out_ctls(spec, &spec->autocfg);
19704 if (err < 0)
19705 return err;
19706
19707 spec->multiout.max_channels = 2;
19708
19709 dig_only:
19710 /* digital only support output */
Takashi Iwai757899a2010-07-30 10:48:14 +020019711 alc_auto_parse_digital(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019712 if (spec->kctls.list)
19713 add_mixer(spec, spec->kctls.list);
19714
19715 add_verb(spec, alc680_init_verbs);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019716
19717 err = alc_auto_add_mic_boost(codec);
19718 if (err < 0)
19719 return err;
19720
19721 return 1;
19722}
19723
19724#define alc680_auto_init_analog_input alc882_auto_init_analog_input
19725
19726/* init callback for auto-configuration model -- overriding the default init */
19727static void alc680_auto_init(struct hda_codec *codec)
19728{
19729 struct alc_spec *spec = codec->spec;
19730 alc680_auto_init_multi_out(codec);
19731 alc680_auto_init_hp_out(codec);
19732 alc680_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020019733 alc_auto_init_digital(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019734 if (spec->unsol_event)
19735 alc_inithook(codec);
19736}
19737
19738/*
19739 * configuration and preset
19740 */
19741static const char *alc680_models[ALC680_MODEL_LAST] = {
Takashi Iwaid4a86d82010-06-23 17:51:26 +020019742 [ALC680_BASE] = "base",
19743 [ALC680_AUTO] = "auto",
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019744};
19745
19746static struct snd_pci_quirk alc680_cfg_tbl[] = {
19747 SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE),
19748 {}
19749};
19750
19751static struct alc_config_preset alc680_presets[] = {
19752 [ALC680_BASE] = {
19753 .mixers = { alc680_base_mixer },
Kailang Yangc69aefa2010-08-17 10:39:22 +020019754 .cap_mixer = alc680_master_capture_mixer,
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019755 .init_verbs = { alc680_init_verbs },
19756 .num_dacs = ARRAY_SIZE(alc680_dac_nids),
19757 .dac_nids = alc680_dac_nids,
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019758 .dig_out_nid = ALC680_DIGOUT_NID,
19759 .num_channel_mode = ARRAY_SIZE(alc680_modes),
19760 .channel_mode = alc680_modes,
Kailang Yangc69aefa2010-08-17 10:39:22 +020019761 .unsol_event = alc680_unsol_event,
19762 .setup = alc680_base_setup,
19763 .init_hook = alc680_inithook,
19764
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019765 },
19766};
19767
19768static int patch_alc680(struct hda_codec *codec)
19769{
19770 struct alc_spec *spec;
19771 int board_config;
19772 int err;
19773
19774 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
19775 if (spec == NULL)
19776 return -ENOMEM;
19777
19778 codec->spec = spec;
19779
19780 board_config = snd_hda_check_board_config(codec, ALC680_MODEL_LAST,
19781 alc680_models,
19782 alc680_cfg_tbl);
19783
19784 if (board_config < 0 || board_config >= ALC680_MODEL_LAST) {
19785 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
19786 codec->chip_name);
19787 board_config = ALC680_AUTO;
19788 }
19789
19790 if (board_config == ALC680_AUTO) {
19791 /* automatic parse from the BIOS config */
19792 err = alc680_parse_auto_config(codec);
19793 if (err < 0) {
19794 alc_free(codec);
19795 return err;
19796 } else if (!err) {
19797 printk(KERN_INFO
19798 "hda_codec: Cannot set up configuration "
19799 "from BIOS. Using base mode...\n");
19800 board_config = ALC680_BASE;
19801 }
19802 }
19803
19804 if (board_config != ALC680_AUTO)
19805 setup_preset(codec, &alc680_presets[board_config]);
19806
19807 spec->stream_analog_playback = &alc680_pcm_analog_playback;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019808 spec->stream_analog_capture = &alc680_pcm_analog_auto_capture;
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019809 spec->stream_digital_playback = &alc680_pcm_digital_playback;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019810 spec->stream_digital_capture = &alc680_pcm_digital_capture;
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019811
19812 if (!spec->adc_nids) {
19813 spec->adc_nids = alc680_adc_nids;
19814 spec->num_adc_nids = ARRAY_SIZE(alc680_adc_nids);
19815 }
19816
19817 if (!spec->cap_mixer)
19818 set_capture_mixer(codec);
19819
19820 spec->vmaster_nid = 0x02;
19821
19822 codec->patch_ops = alc_patch_ops;
19823 if (board_config == ALC680_AUTO)
19824 spec->init_hook = alc680_auto_init;
19825
19826 return 0;
19827}
19828
19829/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070019830 * patch entries
19831 */
Takashi Iwai1289e9e2008-11-27 15:47:11 +010019832static struct hda_codec_preset snd_hda_preset_realtek[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070019833 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010019834 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010019835 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020019836 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010019837 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010019838 { .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +020019839 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010019840 { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019841 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019842 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019843 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
19844 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
19845 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019846 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
Takashi Iwai49535502009-06-30 15:28:30 +020019847 .patch = patch_alc882 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019848 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
19849 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020019850 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Kailang Yangcec27c82010-02-04 14:18:18 +010019851 { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
Kailang Yang6227cdc2010-02-25 08:36:52 +010019852 { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019853 { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019854 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070019855 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai49535502009-06-30 15:28:30 +020019856 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
Clive Messer669faba2008-09-30 15:49:13 +020019857 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
Takashi Iwai49535502009-06-30 15:28:30 +020019858 .patch = patch_alc882 },
Takashi Iwaicb308f92008-04-16 14:13:29 +020019859 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai49535502009-06-30 15:28:30 +020019860 .patch = patch_alc882 },
Kailang Yangdf694da2005-12-05 19:42:22 +010019861 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Takashi Iwai49535502009-06-30 15:28:30 +020019862 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 },
Kailang Yang44426082008-10-15 11:18:05 +020019863 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
Takashi Iwai49535502009-06-30 15:28:30 +020019864 .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010019865 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },
Takashi Iwai49535502009-06-30 15:28:30 +020019866 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010019867 { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070019868 {} /* terminator */
19869};
Takashi Iwai1289e9e2008-11-27 15:47:11 +010019870
19871MODULE_ALIAS("snd-hda-codec-id:10ec*");
19872
19873MODULE_LICENSE("GPL");
19874MODULE_DESCRIPTION("Realtek HD-audio codec");
19875
19876static struct hda_codec_preset_list realtek_list = {
19877 .preset = snd_hda_preset_realtek,
19878 .owner = THIS_MODULE,
19879};
19880
19881static int __init patch_realtek_init(void)
19882{
19883 return snd_hda_add_codec_preset(&realtek_list);
19884}
19885
19886static void __exit patch_realtek_exit(void)
19887{
19888 snd_hda_delete_codec_preset(&realtek_list);
19889}
19890
19891module_init(patch_realtek_init)
19892module_exit(patch_realtek_exit)