blob: be4df4c6fd56bd585ad79b64ddabf6b9344d0f3c [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for ALC 260/880/882 codecs
5 *
Kailang Yangdf694da2005-12-05 19:42:22 +01006 * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
7 * PeiSen Hou <pshou@realtek.com.tw>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * Takashi Iwai <tiwai@suse.de>
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01009 * Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * This driver is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This driver is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/init.h>
27#include <linux/delay.h>
28#include <linux/slab.h>
29#include <linux/pci.h>
30#include <sound/core.h>
Kailang Yang9ad0e492010-09-14 23:22:00 +020031#include <sound/jack.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include "hda_codec.h"
33#include "hda_local.h"
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090034#include "hda_beep.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
Kailang Yangccc656c2006-10-17 12:32:26 +020036#define ALC880_FRONT_EVENT 0x01
37#define ALC880_DCVOL_EVENT 0x02
38#define ALC880_HP_EVENT 0x04
39#define ALC880_MIC_EVENT 0x08
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
41/* ALC880 board config type */
42enum {
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 ALC880_3ST,
44 ALC880_3ST_DIG,
45 ALC880_5ST,
46 ALC880_5ST_DIG,
47 ALC880_W810,
Takashi Iwaidfc0ff62005-05-12 14:31:49 +020048 ALC880_Z71V,
Takashi Iwaib6482d42005-06-27 15:32:43 +020049 ALC880_6ST,
Takashi Iwai16ded522005-06-10 19:58:24 +020050 ALC880_6ST_DIG,
51 ALC880_F1734,
52 ALC880_ASUS,
53 ALC880_ASUS_DIG,
54 ALC880_ASUS_W1V,
Kailang Yangdf694da2005-12-05 19:42:22 +010055 ALC880_ASUS_DIG2,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +010056 ALC880_FUJITSU,
Takashi Iwai16ded522005-06-10 19:58:24 +020057 ALC880_UNIWILL_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +020058 ALC880_UNIWILL,
59 ALC880_UNIWILL_P53,
Kailang Yangdf694da2005-12-05 19:42:22 +010060 ALC880_CLEVO,
61 ALC880_TCL_S700,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010062 ALC880_LG,
Takashi Iwaid6815182006-03-23 16:06:23 +010063 ALC880_LG_LW,
Takashi Iwaidf99cd32008-04-25 15:25:04 +020064 ALC880_MEDION_RIM,
Takashi Iwaie9edcee2005-06-13 14:16:38 +020065#ifdef CONFIG_SND_DEBUG
66 ALC880_TEST,
67#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010068 ALC880_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020069 ALC880_MODEL_LAST /* last tag */
70};
71
72/* ALC260 models */
73enum {
74 ALC260_BASIC,
75 ALC260_HP,
Kailang Yang3f878302008-08-26 13:02:23 +020076 ALC260_HP_DC7600,
Kailang Yangdf694da2005-12-05 19:42:22 +010077 ALC260_HP_3013,
78 ALC260_FUJITSU_S702X,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +010079 ALC260_ACER,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020080 ALC260_WILL,
81 ALC260_REPLACER_672V,
Michael Schwingencc959482009-02-22 18:58:45 +010082 ALC260_FAVORIT100,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +010083#ifdef CONFIG_SND_DEBUG
84 ALC260_TEST,
85#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010086 ALC260_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020087 ALC260_MODEL_LAST /* last tag */
Linus Torvalds1da177e2005-04-16 15:20:36 -070088};
89
Kailang Yangdf694da2005-12-05 19:42:22 +010090/* ALC262 models */
91enum {
92 ALC262_BASIC,
Kailang Yangccc656c2006-10-17 12:32:26 +020093 ALC262_HIPPO,
94 ALC262_HIPPO_1,
Takashi Iwai834be882006-03-01 14:16:17 +010095 ALC262_FUJITSU,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020096 ALC262_HP_BPC,
Kailang Yangcd7509a2007-01-26 18:33:17 +010097 ALC262_HP_BPC_D7000_WL,
98 ALC262_HP_BPC_D7000_WF,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010099 ALC262_HP_TC_T5735,
Kailang Yang8c427222008-01-10 13:03:59 +0100100 ALC262_HP_RP5700,
Takashi Iwai304dcaa2006-07-25 14:51:16 +0200101 ALC262_BENQ_ED8,
Kailang Yang272a5272007-05-14 11:00:38 +0200102 ALC262_SONY_ASSAMD,
Kailang Yang83c34212007-07-05 11:43:05 +0200103 ALC262_BENQ_T31,
Tobin Davisf651b502007-10-26 12:40:47 +0200104 ALC262_ULTRA,
Jiang zhe0e31daf2008-03-20 12:12:39 +0100105 ALC262_LENOVO_3000,
Pascal Terjane8f9ae22008-08-04 14:36:05 +0200106 ALC262_NEC,
Kailang Yang4e555fe2008-08-26 13:05:55 +0200107 ALC262_TOSHIBA_S06,
Hiroshi Miura9f99a632008-08-28 16:09:06 +0200108 ALC262_TOSHIBA_RX1,
Tony Vroonba340e82009-02-02 19:01:30 +0000109 ALC262_TYAN,
Kailang Yangdf694da2005-12-05 19:42:22 +0100110 ALC262_AUTO,
111 ALC262_MODEL_LAST /* last tag */
112};
113
Kailang Yanga361d842007-06-05 12:30:55 +0200114/* ALC268 models */
115enum {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +0200116 ALC267_QUANTA_IL1,
Kailang Yanga361d842007-06-05 12:30:55 +0200117 ALC268_3ST,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200118 ALC268_TOSHIBA,
Takashi Iwaid2738092007-08-16 14:59:45 +0200119 ALC268_ACER,
Takashi Iwaic238b4f2008-11-05 14:57:20 +0100120 ALC268_ACER_DMIC,
Kailang Yang8ef355d2008-08-26 13:10:22 +0200121 ALC268_ACER_ASPIRE_ONE,
Takashi Iwai3866f0b2008-01-15 12:37:42 +0100122 ALC268_DELL,
Mirco Tischlerf12462c2008-02-04 12:33:59 +0100123 ALC268_ZEPTO,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +0100124#ifdef CONFIG_SND_DEBUG
125 ALC268_TEST,
126#endif
Kailang Yanga361d842007-06-05 12:30:55 +0200127 ALC268_AUTO,
128 ALC268_MODEL_LAST /* last tag */
129};
130
Kailang Yangf6a92242007-12-13 16:52:54 +0100131/* ALC269 models */
132enum {
133 ALC269_BASIC,
Kailang Yang60db6b52008-08-26 13:13:00 +0200134 ALC269_QUANTA_FL1,
Kailang Yang84898e82010-02-04 14:16:14 +0100135 ALC269_AMIC,
136 ALC269_DMIC,
137 ALC269VB_AMIC,
138 ALC269VB_DMIC,
Takashi Iwai26f5df22008-11-03 17:39:46 +0100139 ALC269_FUJITSU,
Tony Vroon64154832008-11-06 15:08:49 +0000140 ALC269_LIFEBOOK,
Kailang Yangfe3eb0a2010-08-06 10:02:57 +0200141 ALC271_ACER,
Kailang Yangf6a92242007-12-13 16:52:54 +0100142 ALC269_AUTO,
143 ALC269_MODEL_LAST /* last tag */
144};
145
Kailang Yangdf694da2005-12-05 19:42:22 +0100146/* ALC861 models */
147enum {
148 ALC861_3ST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200149 ALC660_3ST,
Kailang Yangdf694da2005-12-05 19:42:22 +0100150 ALC861_3ST_DIG,
151 ALC861_6ST_DIG,
Takashi Iwai22309c32006-08-09 16:57:28 +0200152 ALC861_UNIWILL_M31,
Tobin Davisa53d1ae2006-10-17 12:00:28 +0200153 ALC861_TOSHIBA,
Mariusz Domanski7cdbff92006-10-23 13:42:56 +0200154 ALC861_ASUS,
Takashi Iwai56bb0ca2006-11-22 11:52:52 +0100155 ALC861_ASUS_LAPTOP,
Kailang Yangdf694da2005-12-05 19:42:22 +0100156 ALC861_AUTO,
157 ALC861_MODEL_LAST,
158};
159
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100160/* ALC861-VD models */
161enum {
162 ALC660VD_3ST,
Mike Crash6963f842007-06-25 12:12:51 +0200163 ALC660VD_3ST_DIG,
Takashi Iwai13c94742008-11-05 08:06:08 +0100164 ALC660VD_ASUS_V1S,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100165 ALC861VD_3ST,
166 ALC861VD_3ST_DIG,
167 ALC861VD_6ST_DIG,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200168 ALC861VD_LENOVO,
Kailang Yang272a5272007-05-14 11:00:38 +0200169 ALC861VD_DALLAS,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200170 ALC861VD_HP,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100171 ALC861VD_AUTO,
172 ALC861VD_MODEL_LAST,
173};
174
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200175/* ALC662 models */
176enum {
177 ALC662_3ST_2ch_DIG,
178 ALC662_3ST_6ch_DIG,
179 ALC662_3ST_6ch,
180 ALC662_5ST_DIG,
181 ALC662_LENOVO_101E,
Kailang Yang291702f2007-10-16 14:28:03 +0200182 ALC662_ASUS_EEEPC_P701,
Kailang Yang8c427222008-01-10 13:03:59 +0100183 ALC662_ASUS_EEEPC_EP20,
Kailang Yang6dda9f42008-05-27 12:05:31 +0200184 ALC663_ASUS_M51VA,
185 ALC663_ASUS_G71V,
186 ALC663_ASUS_H13,
187 ALC663_ASUS_G50V,
Kailang Yangf1d4e282008-08-26 14:03:29 +0200188 ALC662_ECS,
189 ALC663_ASUS_MODE1,
190 ALC662_ASUS_MODE2,
191 ALC663_ASUS_MODE3,
192 ALC663_ASUS_MODE4,
193 ALC663_ASUS_MODE5,
194 ALC663_ASUS_MODE6,
Kailang Yangebb83ee2009-12-17 12:23:00 +0100195 ALC663_ASUS_MODE7,
196 ALC663_ASUS_MODE8,
Kailang Yang622e84c2009-04-21 07:39:04 +0200197 ALC272_DELL,
198 ALC272_DELL_ZM1,
Chris Pockelé9541ba12009-05-12 08:08:53 +0200199 ALC272_SAMSUNG_NC10,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200200 ALC662_AUTO,
201 ALC662_MODEL_LAST,
202};
203
Kailang Yangdf694da2005-12-05 19:42:22 +0100204/* ALC882 models */
205enum {
206 ALC882_3ST_DIG,
207 ALC882_6ST_DIG,
Takashi Iwai4b146cb2006-07-28 14:42:36 +0200208 ALC882_ARIMA,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200209 ALC882_W2JC,
Kailang Yang272a5272007-05-14 11:00:38 +0200210 ALC882_TARGA,
211 ALC882_ASUS_A7J,
Takashi Iwai914759b2007-09-06 14:52:04 +0200212 ALC882_ASUS_A7M,
Tobin Davis9102cd12006-12-15 10:02:12 +0100213 ALC885_MACPRO,
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -0800214 ALC885_MBA21,
Takashi Iwai87350ad2007-08-16 18:19:38 +0200215 ALC885_MBP3,
Kacper Szczesniak41d55452009-05-07 12:47:43 +0200216 ALC885_MB5,
Luke Yelaviche458b1f2010-02-12 16:28:29 +1100217 ALC885_MACMINI3,
Nicola Fagnanic54728d2007-07-19 23:28:52 +0200218 ALC885_IMAC24,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -0800219 ALC885_IMAC91,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200220 ALC883_3ST_2ch_DIG,
221 ALC883_3ST_6ch_DIG,
222 ALC883_3ST_6ch,
223 ALC883_6ST_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +0200224 ALC883_TARGA_DIG,
225 ALC883_TARGA_2ch_DIG,
David Heidelberger64a8be72009-06-08 16:15:18 +0200226 ALC883_TARGA_8ch_DIG,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +0200227 ALC883_ACER,
Tobin Davis2880a862007-08-07 11:50:26 +0200228 ALC883_ACER_ASPIRE,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +0800229 ALC888_ACER_ASPIRE_4930G,
Tony Vroond2fd4b02009-06-21 00:40:10 +0100230 ALC888_ACER_ASPIRE_6530G,
Hector Martin3b315d72009-06-02 10:54:19 +0200231 ALC888_ACER_ASPIRE_8930G,
Denis Kuplyakovfc86f952009-08-25 18:15:59 +0200232 ALC888_ACER_ASPIRE_7730G,
Tobin Davisc07584c2006-10-13 12:32:16 +0200233 ALC883_MEDION,
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +0200234 ALC883_MEDION_WIM2160,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +0100235 ALC883_LAPTOP_EAPD,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200236 ALC883_LENOVO_101E_2ch,
Kailang Yang272a5272007-05-14 11:00:38 +0200237 ALC883_LENOVO_NB0763,
Kailang Yang189609a2007-08-20 11:31:23 +0200238 ALC888_LENOVO_MS7195_DIG,
Kailang Yange2757d52008-08-26 13:17:46 +0200239 ALC888_LENOVO_SKY,
Kailang Yangea1fb292008-08-26 12:58:38 +0200240 ALC883_HAIER_W66,
Claudio Matsuoka4723c022007-07-13 14:36:19 +0200241 ALC888_3ST_HP,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +0100242 ALC888_6ST_DELL,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +0100243 ALC883_MITAC,
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -0430244 ALC883_CLEVO_M540R,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +0100245 ALC883_CLEVO_M720,
Jiang zhefb97dc62008-03-06 11:07:11 +0100246 ALC883_FUJITSU_PI2515,
Vincent Petryef8ef5f2008-11-23 11:31:41 +0800247 ALC888_FUJITSU_XA3530,
Jiang zhe17bba1b2008-06-04 12:11:07 +0200248 ALC883_3ST_6ch_INTEL,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +0200249 ALC889A_INTEL,
250 ALC889_INTEL,
Kailang Yange2757d52008-08-26 13:17:46 +0200251 ALC888_ASUS_M90V,
252 ALC888_ASUS_EEE1601,
Torben Schulzeb4c41d2009-05-18 15:02:35 +0200253 ALC889A_MB31,
Wu Fengguang3ab90932008-11-17 09:51:09 +0100254 ALC1200_ASUS_P5Q,
Guido Günther3e1647c2009-06-05 00:47:26 +0200255 ALC883_SONY_VAIO_TT,
Takashi Iwai49535502009-06-30 15:28:30 +0200256 ALC882_AUTO,
257 ALC882_MODEL_LAST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200258};
259
Takashi Iwaid4a86d82010-06-23 17:51:26 +0200260/* ALC680 models */
261enum {
262 ALC680_BASE,
263 ALC680_AUTO,
264 ALC680_MODEL_LAST,
265};
266
Kailang Yangdf694da2005-12-05 19:42:22 +0100267/* for GPIO Poll */
268#define GPIO_MASK 0x03
269
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200270/* extra amp-initialization sequence types */
271enum {
272 ALC_INIT_NONE,
273 ALC_INIT_DEFAULT,
274 ALC_INIT_GPIO1,
275 ALC_INIT_GPIO2,
276 ALC_INIT_GPIO3,
277};
278
Takashi Iwai6c819492009-08-10 18:47:44 +0200279struct alc_mic_route {
280 hda_nid_t pin;
281 unsigned char mux_idx;
282 unsigned char amix_idx;
283};
284
Kailang Yang9ad0e492010-09-14 23:22:00 +0200285struct alc_jack {
286 hda_nid_t nid;
287 int type;
288 struct snd_jack *jack;
289};
290
Takashi Iwai6c819492009-08-10 18:47:44 +0200291#define MUX_IDX_UNDEF ((unsigned char)-1)
292
Kailang Yangda00c242010-03-19 11:23:45 +0100293struct alc_customize_define {
294 unsigned int sku_cfg;
295 unsigned char port_connectivity;
296 unsigned char check_sum;
297 unsigned char customization;
298 unsigned char external_amp;
299 unsigned int enable_pcbeep:1;
300 unsigned int platform_type:1;
301 unsigned int swap:1;
302 unsigned int override:1;
David Henningsson90622912010-10-14 14:50:18 +0200303 unsigned int fixup:1; /* Means that this sku is set by driver, not read from hw */
Kailang Yangda00c242010-03-19 11:23:45 +0100304};
305
Takashi Iwaib5bfbc62011-01-13 14:22:32 +0100306struct alc_fixup;
307
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308struct alc_spec {
309 /* codec parameterization */
Kailang Yangdf694da2005-12-05 19:42:22 +0100310 struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 unsigned int num_mixers;
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100312 struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Takashi Iwai45bdd1c2009-02-06 16:11:25 +0100313 unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
Takashi Iwai2d9c6482009-10-13 08:06:55 +0200315 const struct hda_verb *init_verbs[10]; /* initialization verbs
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200316 * don't forget NULL
317 * termination!
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200318 */
319 unsigned int num_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
Takashi Iwaiaa563af2009-07-31 10:05:11 +0200321 char stream_name_analog[32]; /* analog PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 struct hda_pcm_stream *stream_analog_playback;
323 struct hda_pcm_stream *stream_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +0100324 struct hda_pcm_stream *stream_analog_alt_playback;
325 struct hda_pcm_stream *stream_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
Takashi Iwaiaa563af2009-07-31 10:05:11 +0200327 char stream_name_digital[32]; /* digital PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 struct hda_pcm_stream *stream_digital_playback;
329 struct hda_pcm_stream *stream_digital_capture;
330
331 /* playback */
Takashi Iwai16ded522005-06-10 19:58:24 +0200332 struct hda_multi_out multiout; /* playback set-up
333 * max_channels, dacs must be set
334 * dig_out_nid and hp_nid are optional
335 */
Takashi Iwai63300792008-01-24 15:31:36 +0100336 hda_nid_t alt_dac_nid;
Takashi Iwai6a05ac42009-02-13 11:19:09 +0100337 hda_nid_t slave_dig_outs[3]; /* optional - for auto-parsing */
Takashi Iwai8c441982009-01-20 18:30:20 +0100338 int dig_out_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
340 /* capture */
341 unsigned int num_adc_nids;
342 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100343 hda_nid_t *capsrc_nids;
Takashi Iwai16ded522005-06-10 19:58:24 +0200344 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345
Takashi Iwai840b64c2010-07-13 22:49:01 +0200346 /* capture setup for dynamic dual-adc switch */
347 unsigned int cur_adc_idx;
348 hda_nid_t cur_adc;
349 unsigned int cur_adc_stream_tag;
350 unsigned int cur_adc_format;
351
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 /* capture source */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200353 unsigned int num_mux_defs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 const struct hda_input_mux *input_mux;
355 unsigned int cur_mux[3];
Takashi Iwai6c819492009-08-10 18:47:44 +0200356 struct alc_mic_route ext_mic;
357 struct alc_mic_route int_mic;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
359 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100360 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 int num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200362 int need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200363 int const_channel_count;
364 int ext_channel_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
366 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100367 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200368
Kailang Yang9ad0e492010-09-14 23:22:00 +0200369 /* jack detection */
370 struct snd_array jacks;
371
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200372 /* dynamic controls, init_verbs and input_mux */
373 struct auto_pin_cfg autocfg;
Kailang Yangda00c242010-03-19 11:23:45 +0100374 struct alc_customize_define cdefine;
Takashi Iwai603c4012008-07-30 15:01:44 +0200375 struct snd_array kctls;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200376 struct hda_input_mux private_imux[3];
Takashi Iwai41923e42007-10-22 17:20:10 +0200377 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai49535502009-06-30 15:28:30 +0200378 hda_nid_t private_adc_nids[AUTO_CFG_MAX_OUTS];
379 hda_nid_t private_capsrc_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai834be882006-03-01 14:16:17 +0100380
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100381 /* hooks */
382 void (*init_hook)(struct hda_codec *codec);
383 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
Hector Martinf5de24b2009-12-20 22:51:31 +0100384#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -0500385 void (*power_hook)(struct hda_codec *codec);
Hector Martinf5de24b2009-12-20 22:51:31 +0100386#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100387
Takashi Iwai834be882006-03-01 14:16:17 +0100388 /* for pin sensing */
389 unsigned int sense_updated: 1;
390 unsigned int jack_present: 1;
Takashi Iwaibec15c32008-01-28 18:16:30 +0100391 unsigned int master_sw: 1;
Takashi Iwai6c819492009-08-10 18:47:44 +0200392 unsigned int auto_mic:1;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200393
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100394 /* other flags */
395 unsigned int no_analog :1; /* digital I/O only */
Takashi Iwai840b64c2010-07-13 22:49:01 +0200396 unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200397 int init_amp;
Takashi Iwaid433a672010-09-20 15:11:54 +0200398 int codec_variant; /* flag for other variants */
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100399
Takashi Iwai2134ea42008-01-10 16:53:55 +0100400 /* for virtual master */
401 hda_nid_t vmaster_nid;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200402#ifdef CONFIG_SND_HDA_POWER_SAVE
403 struct hda_loopback_check loopback;
404#endif
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200405
406 /* for PLL fix */
407 hda_nid_t pll_nid;
408 unsigned int pll_coef_idx, pll_coef_bit;
Takashi Iwaib5bfbc62011-01-13 14:22:32 +0100409
410 /* fix-up list */
411 int fixup_id;
412 const struct alc_fixup *fixup_list;
413 const char *fixup_name;
Kailang Yangdf694da2005-12-05 19:42:22 +0100414};
415
416/*
417 * configuration template - to be copied to the spec instance
418 */
419struct alc_config_preset {
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200420 struct snd_kcontrol_new *mixers[5]; /* should be identical size
421 * with spec
422 */
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100423 struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Kailang Yangdf694da2005-12-05 19:42:22 +0100424 const struct hda_verb *init_verbs[5];
425 unsigned int num_dacs;
426 hda_nid_t *dac_nids;
427 hda_nid_t dig_out_nid; /* optional */
428 hda_nid_t hp_nid; /* optional */
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800429 hda_nid_t *slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100430 unsigned int num_adc_nids;
431 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100432 hda_nid_t *capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100433 hda_nid_t dig_in_nid;
434 unsigned int num_channel_mode;
435 const struct hda_channel_mode *channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200436 int need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200437 int const_channel_count;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200438 unsigned int num_mux_defs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100439 const struct hda_input_mux *input_mux;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100440 void (*unsol_event)(struct hda_codec *, unsigned int);
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200441 void (*setup)(struct hda_codec *);
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100442 void (*init_hook)(struct hda_codec *);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200443#ifdef CONFIG_SND_HDA_POWER_SAVE
444 struct hda_amp_list *loopbacks;
Daniel T Chenc97259d2009-12-27 18:52:08 -0500445 void (*power_hook)(struct hda_codec *codec);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200446#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447};
448
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449
450/*
451 * input MUX handling
452 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200453static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
454 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455{
456 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
457 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200458 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
459 if (mux_idx >= spec->num_mux_defs)
460 mux_idx = 0;
Takashi Iwai53111142010-03-08 12:13:07 +0100461 if (!spec->input_mux[mux_idx].num_items && mux_idx > 0)
462 mux_idx = 0;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200463 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464}
465
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200466static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
467 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468{
469 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
470 struct alc_spec *spec = codec->spec;
471 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
472
473 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
474 return 0;
475}
476
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200477static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
478 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479{
480 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
481 struct alc_spec *spec = codec->spec;
Takashi Iwaicd896c32008-11-18 12:36:33 +0100482 const struct hda_input_mux *imux;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwaicd896c32008-11-18 12:36:33 +0100484 unsigned int mux_idx;
Takashi Iwaie1406342008-02-11 18:32:32 +0100485 hda_nid_t nid = spec->capsrc_nids ?
486 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Takashi Iwai0169b6b2009-06-22 10:50:19 +0200487 unsigned int type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488
Takashi Iwaicd896c32008-11-18 12:36:33 +0100489 mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
490 imux = &spec->input_mux[mux_idx];
Takashi Iwai53111142010-03-08 12:13:07 +0100491 if (!imux->num_items && mux_idx > 0)
492 imux = &spec->input_mux[0];
Takashi Iwaicd896c32008-11-18 12:36:33 +0100493
Takashi Iwaia22d5432009-07-27 12:54:26 +0200494 type = get_wcaps_type(get_wcaps(codec, nid));
Takashi Iwai0169b6b2009-06-22 10:50:19 +0200495 if (type == AC_WID_AUD_MIX) {
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100496 /* Matrix-mixer style (e.g. ALC882) */
497 unsigned int *cur_val = &spec->cur_mux[adc_idx];
498 unsigned int i, idx;
499
500 idx = ucontrol->value.enumerated.item[0];
501 if (idx >= imux->num_items)
502 idx = imux->num_items - 1;
503 if (*cur_val == idx)
504 return 0;
505 for (i = 0; i < imux->num_items; i++) {
506 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
507 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
508 imux->items[i].index,
509 HDA_AMP_MUTE, v);
510 }
511 *cur_val = idx;
512 return 1;
513 } else {
514 /* MUX style (e.g. ALC880) */
Takashi Iwaicd896c32008-11-18 12:36:33 +0100515 return snd_hda_input_mux_put(codec, imux, ucontrol, nid,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100516 &spec->cur_mux[adc_idx]);
517 }
518}
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200519
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520/*
521 * channel mode setting
522 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200523static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
524 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525{
526 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
527 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100528 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
529 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530}
531
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200532static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
533 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534{
535 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
536 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100537 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200538 spec->num_channel_mode,
Hector Martin3b315d72009-06-02 10:54:19 +0200539 spec->ext_channel_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540}
541
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200542static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
543 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544{
545 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
546 struct alc_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200547 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
548 spec->num_channel_mode,
Hector Martin3b315d72009-06-02 10:54:19 +0200549 &spec->ext_channel_count);
550 if (err >= 0 && !spec->const_channel_count) {
551 spec->multiout.max_channels = spec->ext_channel_count;
552 if (spec->need_dac_fix)
553 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
554 }
Takashi Iwai4e195a72006-07-28 14:47:34 +0200555 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556}
557
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100559 * Control the mode of pin widget settings via the mixer. "pc" is used
Kailang Yangea1fb292008-08-26 12:58:38 +0200560 * instead of "%" to avoid consequences of accidently treating the % as
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100561 * being part of a format specifier. Maximum allowed length of a value is
562 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100563 *
564 * Note: some retasking pin complexes seem to ignore requests for input
565 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
566 * are requested. Therefore order this list so that this behaviour will not
567 * cause problems when mixer clients move through the enum sequentially.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200568 * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
569 * March 2006.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200570 */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100571static char *alc_pin_mode_names[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100572 "Mic 50pc bias", "Mic 80pc bias",
573 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100574};
575static unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100576 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100577};
578/* The control can present all 5 options, or it can limit the options based
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200579 * in the pin being assumed to be exclusively an input or an output pin. In
580 * addition, "input" pins may or may not process the mic bias option
581 * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
582 * accept requests for bias as of chip versions up to March 2006) and/or
583 * wiring in the computer.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100584 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200585#define ALC_PIN_DIR_IN 0x00
586#define ALC_PIN_DIR_OUT 0x01
587#define ALC_PIN_DIR_INOUT 0x02
588#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
589#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100590
Kailang Yangea1fb292008-08-26 12:58:38 +0200591/* Info about the pin modes supported by the different pin direction modes.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100592 * For each direction the minimum and maximum values are given.
593 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200594static signed char alc_pin_mode_dir_info[5][2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100595 { 0, 2 }, /* ALC_PIN_DIR_IN */
596 { 3, 4 }, /* ALC_PIN_DIR_OUT */
597 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200598 { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
599 { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100600};
601#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
602#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
603#define alc_pin_mode_n_items(_dir) \
604 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
605
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200606static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
607 struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200608{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100609 unsigned int item_num = uinfo->value.enumerated.item;
610 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
611
612 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200613 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100614 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
615
616 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
617 item_num = alc_pin_mode_min(dir);
618 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200619 return 0;
620}
621
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200622static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
623 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200624{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100625 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200626 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
627 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100628 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200629 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200630 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
631 AC_VERB_GET_PIN_WIDGET_CONTROL,
632 0x00);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200633
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100634 /* Find enumerated value for current pinctl setting */
635 i = alc_pin_mode_min(dir);
Roel Kluin4b35d2c2009-08-02 13:30:45 +0200636 while (i <= alc_pin_mode_max(dir) && alc_pin_mode_values[i] != pinctl)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100637 i++;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200638 *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100639 return 0;
640}
641
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200642static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
643 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100644{
645 signed int change;
646 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
647 hda_nid_t nid = kcontrol->private_value & 0xffff;
648 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
649 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200650 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
651 AC_VERB_GET_PIN_WIDGET_CONTROL,
652 0x00);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100653
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200654 if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100655 val = alc_pin_mode_min(dir);
656
657 change = pinctl != alc_pin_mode_values[val];
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100658 if (change) {
659 /* Set pin mode to that requested */
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200660 snd_hda_codec_write_cache(codec, nid, 0,
661 AC_VERB_SET_PIN_WIDGET_CONTROL,
662 alc_pin_mode_values[val]);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100663
Kailang Yangea1fb292008-08-26 12:58:38 +0200664 /* Also enable the retasking pin's input/output as required
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100665 * for the requested pin mode. Enum values of 2 or less are
666 * input modes.
667 *
668 * Dynamically switching the input/output buffers probably
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200669 * reduces noise slightly (particularly on input) so we'll
670 * do it. However, having both input and output buffers
671 * enabled simultaneously doesn't seem to be problematic if
672 * this turns out to be necessary in the future.
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100673 */
674 if (val <= 2) {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200675 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
676 HDA_AMP_MUTE, HDA_AMP_MUTE);
677 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
678 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100679 } else {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200680 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
681 HDA_AMP_MUTE, HDA_AMP_MUTE);
682 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
683 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100684 }
685 }
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200686 return change;
687}
688
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100689#define ALC_PIN_MODE(xname, nid, dir) \
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200690 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100691 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100692 .info = alc_pin_mode_info, \
693 .get = alc_pin_mode_get, \
694 .put = alc_pin_mode_put, \
695 .private_value = nid | (dir<<16) }
Kailang Yangdf694da2005-12-05 19:42:22 +0100696
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100697/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
698 * together using a mask with more than one bit set. This control is
699 * currently used only by the ALC260 test model. At this stage they are not
700 * needed for any "production" models.
701 */
702#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200703#define alc_gpio_data_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200704
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200705static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
706 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100707{
708 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
709 hda_nid_t nid = kcontrol->private_value & 0xffff;
710 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
711 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200712 unsigned int val = snd_hda_codec_read(codec, nid, 0,
713 AC_VERB_GET_GPIO_DATA, 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100714
715 *valp = (val & mask) != 0;
716 return 0;
717}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200718static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
719 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100720{
721 signed int change;
722 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
723 hda_nid_t nid = kcontrol->private_value & 0xffff;
724 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
725 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200726 unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
727 AC_VERB_GET_GPIO_DATA,
728 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100729
730 /* Set/unset the masked GPIO bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200731 change = (val == 0 ? 0 : mask) != (gpio_data & mask);
732 if (val == 0)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100733 gpio_data &= ~mask;
734 else
735 gpio_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200736 snd_hda_codec_write_cache(codec, nid, 0,
737 AC_VERB_SET_GPIO_DATA, gpio_data);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100738
739 return change;
740}
741#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
742 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100743 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100744 .info = alc_gpio_data_info, \
745 .get = alc_gpio_data_get, \
746 .put = alc_gpio_data_put, \
747 .private_value = nid | (mask<<16) }
748#endif /* CONFIG_SND_DEBUG */
749
Jonathan Woithe92621f12006-02-28 11:47:47 +0100750/* A switch control to allow the enabling of the digital IO pins on the
751 * ALC260. This is incredibly simplistic; the intention of this control is
752 * to provide something in the test model allowing digital outputs to be
753 * identified if present. If models are found which can utilise these
754 * outputs a more complete mixer control can be devised for those models if
755 * necessary.
756 */
757#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200758#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200759
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200760static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
761 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100762{
763 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
764 hda_nid_t nid = kcontrol->private_value & 0xffff;
765 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
766 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200767 unsigned int val = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100768 AC_VERB_GET_DIGI_CONVERT_1, 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100769
770 *valp = (val & mask) != 0;
771 return 0;
772}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200773static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
774 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100775{
776 signed int change;
777 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
778 hda_nid_t nid = kcontrol->private_value & 0xffff;
779 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
780 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200781 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100782 AC_VERB_GET_DIGI_CONVERT_1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200783 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100784
785 /* Set/unset the masked control bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200786 change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100787 if (val==0)
788 ctrl_data &= ~mask;
789 else
790 ctrl_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200791 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
792 ctrl_data);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100793
794 return change;
795}
796#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
797 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100798 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe92621f12006-02-28 11:47:47 +0100799 .info = alc_spdif_ctrl_info, \
800 .get = alc_spdif_ctrl_get, \
801 .put = alc_spdif_ctrl_put, \
802 .private_value = nid | (mask<<16) }
803#endif /* CONFIG_SND_DEBUG */
804
Jonathan Woithef8225f62008-01-08 12:16:54 +0100805/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
806 * Again, this is only used in the ALC26x test models to help identify when
807 * the EAPD line must be asserted for features to work.
808 */
809#ifdef CONFIG_SND_DEBUG
810#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
811
812static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
813 struct snd_ctl_elem_value *ucontrol)
814{
815 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
816 hda_nid_t nid = kcontrol->private_value & 0xffff;
817 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
818 long *valp = ucontrol->value.integer.value;
819 unsigned int val = snd_hda_codec_read(codec, nid, 0,
820 AC_VERB_GET_EAPD_BTLENABLE, 0x00);
821
822 *valp = (val & mask) != 0;
823 return 0;
824}
825
826static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
827 struct snd_ctl_elem_value *ucontrol)
828{
829 int change;
830 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
831 hda_nid_t nid = kcontrol->private_value & 0xffff;
832 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
833 long val = *ucontrol->value.integer.value;
834 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
835 AC_VERB_GET_EAPD_BTLENABLE,
836 0x00);
837
838 /* Set/unset the masked control bit(s) as needed */
839 change = (!val ? 0 : mask) != (ctrl_data & mask);
840 if (!val)
841 ctrl_data &= ~mask;
842 else
843 ctrl_data |= mask;
844 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
845 ctrl_data);
846
847 return change;
848}
849
850#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
851 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100852 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithef8225f62008-01-08 12:16:54 +0100853 .info = alc_eapd_ctrl_info, \
854 .get = alc_eapd_ctrl_get, \
855 .put = alc_eapd_ctrl_put, \
856 .private_value = nid | (mask<<16) }
857#endif /* CONFIG_SND_DEBUG */
858
Kailang Yangdf694da2005-12-05 19:42:22 +0100859/*
Takashi Iwai23f0c042009-02-26 13:03:58 +0100860 * set up the input pin config (depending on the given auto-pin type)
861 */
862static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
863 int auto_pin_type)
864{
865 unsigned int val = PIN_IN;
866
Takashi Iwai86e29592010-09-09 14:50:17 +0200867 if (auto_pin_type == AUTO_PIN_MIC) {
Takashi Iwai23f0c042009-02-26 13:03:58 +0100868 unsigned int pincap;
Takashi Iwai954a29c2010-07-30 10:55:44 +0200869 unsigned int oldval;
870 oldval = snd_hda_codec_read(codec, nid, 0,
871 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
Takashi Iwai1327a322009-03-23 13:07:47 +0100872 pincap = snd_hda_query_pin_caps(codec, nid);
Takashi Iwai23f0c042009-02-26 13:03:58 +0100873 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
Takashi Iwai954a29c2010-07-30 10:55:44 +0200874 /* if the default pin setup is vref50, we give it priority */
875 if ((pincap & AC_PINCAP_VREF_80) && oldval != PIN_VREF50)
Takashi Iwai23f0c042009-02-26 13:03:58 +0100876 val = PIN_VREF80;
Takashi Iwai461c6c32009-05-25 08:06:02 +0200877 else if (pincap & AC_PINCAP_VREF_50)
878 val = PIN_VREF50;
879 else if (pincap & AC_PINCAP_VREF_100)
880 val = PIN_VREF100;
881 else if (pincap & AC_PINCAP_VREF_GRD)
882 val = PIN_VREFGRD;
Takashi Iwai23f0c042009-02-26 13:03:58 +0100883 }
884 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
885}
886
Takashi Iwaif6837bb2010-09-20 14:56:32 +0200887static void alc_fixup_autocfg_pin_nums(struct hda_codec *codec)
888{
889 struct alc_spec *spec = codec->spec;
890 struct auto_pin_cfg *cfg = &spec->autocfg;
891
892 if (!cfg->line_outs) {
893 while (cfg->line_outs < AUTO_CFG_MAX_OUTS &&
894 cfg->line_out_pins[cfg->line_outs])
895 cfg->line_outs++;
896 }
897 if (!cfg->speaker_outs) {
898 while (cfg->speaker_outs < AUTO_CFG_MAX_OUTS &&
899 cfg->speaker_pins[cfg->speaker_outs])
900 cfg->speaker_outs++;
901 }
902 if (!cfg->hp_outs) {
903 while (cfg->hp_outs < AUTO_CFG_MAX_OUTS &&
904 cfg->hp_pins[cfg->hp_outs])
905 cfg->hp_outs++;
906 }
907}
908
Takashi Iwai23f0c042009-02-26 13:03:58 +0100909/*
Takashi Iwaid88897e2008-10-31 15:01:37 +0100910 */
911static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix)
912{
913 if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
914 return;
915 spec->mixers[spec->num_mixers++] = mix;
916}
917
918static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
919{
920 if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
921 return;
922 spec->init_verbs[spec->num_init_verbs++] = verb;
923}
924
925/*
Kailang Yangdf694da2005-12-05 19:42:22 +0100926 * set up from the preset table
927 */
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200928static void setup_preset(struct hda_codec *codec,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200929 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100930{
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200931 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +0100932 int i;
933
934 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100935 add_mixer(spec, preset->mixers[i]);
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100936 spec->cap_mixer = preset->cap_mixer;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200937 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
938 i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100939 add_verb(spec, preset->init_verbs[i]);
Kailang Yangea1fb292008-08-26 12:58:38 +0200940
Kailang Yangdf694da2005-12-05 19:42:22 +0100941 spec->channel_mode = preset->channel_mode;
942 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200943 spec->need_dac_fix = preset->need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200944 spec->const_channel_count = preset->const_channel_count;
Kailang Yangdf694da2005-12-05 19:42:22 +0100945
Hector Martin3b315d72009-06-02 10:54:19 +0200946 if (preset->const_channel_count)
947 spec->multiout.max_channels = preset->const_channel_count;
948 else
949 spec->multiout.max_channels = spec->channel_mode[0].channels;
950 spec->ext_channel_count = spec->channel_mode[0].channels;
Kailang Yangdf694da2005-12-05 19:42:22 +0100951
952 spec->multiout.num_dacs = preset->num_dacs;
953 spec->multiout.dac_nids = preset->dac_nids;
954 spec->multiout.dig_out_nid = preset->dig_out_nid;
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800955 spec->multiout.slave_dig_outs = preset->slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100956 spec->multiout.hp_nid = preset->hp_nid;
Kailang Yangea1fb292008-08-26 12:58:38 +0200957
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200958 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200959 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200960 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100961 spec->input_mux = preset->input_mux;
962
963 spec->num_adc_nids = preset->num_adc_nids;
964 spec->adc_nids = preset->adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100965 spec->capsrc_nids = preset->capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100966 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100967
968 spec->unsol_event = preset->unsol_event;
969 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200970#ifdef CONFIG_SND_HDA_POWER_SAVE
Hector Martinf5de24b2009-12-20 22:51:31 +0100971 spec->power_hook = preset->power_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200972 spec->loopback.amplist = preset->loopbacks;
973#endif
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200974
975 if (preset->setup)
976 preset->setup(codec);
Takashi Iwaif6837bb2010-09-20 14:56:32 +0200977
978 alc_fixup_autocfg_pin_nums(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +0100979}
980
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200981/* Enable GPIO mask and set output */
982static struct hda_verb alc_gpio1_init_verbs[] = {
983 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
984 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
985 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
986 { }
987};
988
989static struct hda_verb alc_gpio2_init_verbs[] = {
990 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
991 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
992 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
993 { }
994};
995
Kailang Yangbdd148a2007-05-08 15:19:08 +0200996static struct hda_verb alc_gpio3_init_verbs[] = {
997 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
998 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
999 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
1000 { }
1001};
1002
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02001003/*
1004 * Fix hardware PLL issue
1005 * On some codecs, the analog PLL gating control must be off while
1006 * the default value is 1.
1007 */
1008static void alc_fix_pll(struct hda_codec *codec)
1009{
1010 struct alc_spec *spec = codec->spec;
1011 unsigned int val;
1012
1013 if (!spec->pll_nid)
1014 return;
1015 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
1016 spec->pll_coef_idx);
1017 val = snd_hda_codec_read(codec, spec->pll_nid, 0,
1018 AC_VERB_GET_PROC_COEF, 0);
1019 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
1020 spec->pll_coef_idx);
1021 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
1022 val & ~(1 << spec->pll_coef_bit));
1023}
1024
1025static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
1026 unsigned int coef_idx, unsigned int coef_bit)
1027{
1028 struct alc_spec *spec = codec->spec;
1029 spec->pll_nid = nid;
1030 spec->pll_coef_idx = coef_idx;
1031 spec->pll_coef_bit = coef_bit;
1032 alc_fix_pll(codec);
1033}
1034
Kailang Yang9ad0e492010-09-14 23:22:00 +02001035#ifdef CONFIG_SND_HDA_INPUT_JACK
1036static void alc_free_jack_priv(struct snd_jack *jack)
1037{
1038 struct alc_jack *jacks = jack->private_data;
1039 jacks->nid = 0;
1040 jacks->jack = NULL;
1041}
1042
1043static int alc_add_jack(struct hda_codec *codec,
1044 hda_nid_t nid, int type)
1045{
1046 struct alc_spec *spec;
1047 struct alc_jack *jack;
1048 const char *name;
1049 int err;
1050
1051 spec = codec->spec;
1052 snd_array_init(&spec->jacks, sizeof(*jack), 32);
1053 jack = snd_array_new(&spec->jacks);
1054 if (!jack)
1055 return -ENOMEM;
1056
1057 jack->nid = nid;
1058 jack->type = type;
1059 name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ;
1060
1061 err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
1062 if (err < 0)
1063 return err;
1064 jack->jack->private_data = jack;
1065 jack->jack->private_free = alc_free_jack_priv;
1066 return 0;
1067}
1068
1069static void alc_report_jack(struct hda_codec *codec, hda_nid_t nid)
1070{
1071 struct alc_spec *spec = codec->spec;
1072 struct alc_jack *jacks = spec->jacks.list;
1073
1074 if (jacks) {
1075 int i;
1076 for (i = 0; i < spec->jacks.used; i++) {
1077 if (jacks->nid == nid) {
1078 unsigned int present;
1079 present = snd_hda_jack_detect(codec, nid);
1080
1081 present = (present) ? jacks->type : 0;
1082
1083 snd_jack_report(jacks->jack, present);
1084 }
1085 jacks++;
1086 }
1087 }
1088}
1089
1090static int alc_init_jacks(struct hda_codec *codec)
1091{
1092 struct alc_spec *spec = codec->spec;
1093 int err;
1094 unsigned int hp_nid = spec->autocfg.hp_pins[0];
1095 unsigned int mic_nid = spec->ext_mic.pin;
1096
Takashi Iwai265a0242010-09-21 11:26:21 +02001097 if (hp_nid) {
1098 err = alc_add_jack(codec, hp_nid, SND_JACK_HEADPHONE);
1099 if (err < 0)
1100 return err;
1101 alc_report_jack(codec, hp_nid);
1102 }
Kailang Yang9ad0e492010-09-14 23:22:00 +02001103
Takashi Iwai265a0242010-09-21 11:26:21 +02001104 if (mic_nid) {
1105 err = alc_add_jack(codec, mic_nid, SND_JACK_MICROPHONE);
1106 if (err < 0)
1107 return err;
1108 alc_report_jack(codec, mic_nid);
1109 }
Kailang Yang9ad0e492010-09-14 23:22:00 +02001110
1111 return 0;
1112}
1113#else
1114static inline void alc_report_jack(struct hda_codec *codec, hda_nid_t nid)
1115{
1116}
1117
1118static inline int alc_init_jacks(struct hda_codec *codec)
1119{
1120 return 0;
1121}
1122#endif
1123
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001124static void alc_automute_speaker(struct hda_codec *codec, int pinctl)
Kailang Yangc9b58002007-10-16 14:30:01 +02001125{
1126 struct alc_spec *spec = codec->spec;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001127 unsigned int mute;
1128 hda_nid_t nid;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001129 int i;
Kailang Yangc9b58002007-10-16 14:30:01 +02001130
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001131 spec->jack_present = 0;
1132 for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
1133 nid = spec->autocfg.hp_pins[i];
1134 if (!nid)
1135 break;
1136 if (snd_hda_jack_detect(codec, nid)) {
1137 spec->jack_present = 1;
1138 break;
1139 }
Kailang Yang9ad0e492010-09-14 23:22:00 +02001140 alc_report_jack(codec, spec->autocfg.hp_pins[i]);
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001141 }
1142
1143 mute = spec->jack_present ? HDA_AMP_MUTE : 0;
1144 /* Toggle internal speakers muting */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001145 for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
1146 nid = spec->autocfg.speaker_pins[i];
1147 if (!nid)
1148 break;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001149 if (pinctl) {
1150 snd_hda_codec_write(codec, nid, 0,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001151 AC_VERB_SET_PIN_WIDGET_CONTROL,
1152 spec->jack_present ? 0 : PIN_OUT);
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001153 } else {
1154 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
1155 HDA_AMP_MUTE, mute);
1156 }
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001157 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001158}
1159
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001160static void alc_automute_pin(struct hda_codec *codec)
1161{
1162 alc_automute_speaker(codec, 1);
1163}
1164
Takashi Iwai6c819492009-08-10 18:47:44 +02001165static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
1166 hda_nid_t nid)
1167{
1168 hda_nid_t conn[HDA_MAX_NUM_INPUTS];
1169 int i, nums;
1170
1171 nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
1172 for (i = 0; i < nums; i++)
1173 if (conn[i] == nid)
1174 return i;
1175 return -1;
1176}
1177
Takashi Iwai840b64c2010-07-13 22:49:01 +02001178/* switch the current ADC according to the jack state */
1179static void alc_dual_mic_adc_auto_switch(struct hda_codec *codec)
1180{
1181 struct alc_spec *spec = codec->spec;
1182 unsigned int present;
1183 hda_nid_t new_adc;
1184
1185 present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
1186 if (present)
1187 spec->cur_adc_idx = 1;
1188 else
1189 spec->cur_adc_idx = 0;
1190 new_adc = spec->adc_nids[spec->cur_adc_idx];
1191 if (spec->cur_adc && spec->cur_adc != new_adc) {
1192 /* stream is running, let's swap the current ADC */
Takashi Iwaif0cea792010-08-13 11:56:53 +02001193 __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
Takashi Iwai840b64c2010-07-13 22:49:01 +02001194 spec->cur_adc = new_adc;
1195 snd_hda_codec_setup_stream(codec, new_adc,
1196 spec->cur_adc_stream_tag, 0,
1197 spec->cur_adc_format);
1198 }
1199}
1200
Kailang Yang7fb0d782008-10-15 11:12:35 +02001201static void alc_mic_automute(struct hda_codec *codec)
1202{
1203 struct alc_spec *spec = codec->spec;
Takashi Iwai6c819492009-08-10 18:47:44 +02001204 struct alc_mic_route *dead, *alive;
1205 unsigned int present, type;
1206 hda_nid_t cap_nid;
Kailang Yang7fb0d782008-10-15 11:12:35 +02001207
Takashi Iwaib59bdf32009-08-11 09:47:30 +02001208 if (!spec->auto_mic)
1209 return;
Takashi Iwai6c819492009-08-10 18:47:44 +02001210 if (!spec->int_mic.pin || !spec->ext_mic.pin)
1211 return;
1212 if (snd_BUG_ON(!spec->adc_nids))
1213 return;
1214
Takashi Iwai840b64c2010-07-13 22:49:01 +02001215 if (spec->dual_adc_switch) {
1216 alc_dual_mic_adc_auto_switch(codec);
1217 return;
1218 }
1219
Takashi Iwai6c819492009-08-10 18:47:44 +02001220 cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0];
1221
Wu Fengguang864f92b2009-11-18 12:38:02 +08001222 present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
Takashi Iwai6c819492009-08-10 18:47:44 +02001223 if (present) {
1224 alive = &spec->ext_mic;
1225 dead = &spec->int_mic;
1226 } else {
1227 alive = &spec->int_mic;
1228 dead = &spec->ext_mic;
1229 }
1230
Takashi Iwai6c819492009-08-10 18:47:44 +02001231 type = get_wcaps_type(get_wcaps(codec, cap_nid));
1232 if (type == AC_WID_AUD_MIX) {
1233 /* Matrix-mixer style (e.g. ALC882) */
1234 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1235 alive->mux_idx,
1236 HDA_AMP_MUTE, 0);
1237 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1238 dead->mux_idx,
1239 HDA_AMP_MUTE, HDA_AMP_MUTE);
1240 } else {
1241 /* MUX style (e.g. ALC880) */
1242 snd_hda_codec_write_cache(codec, cap_nid, 0,
1243 AC_VERB_SET_CONNECT_SEL,
1244 alive->mux_idx);
1245 }
Kailang Yang9ad0e492010-09-14 23:22:00 +02001246 alc_report_jack(codec, spec->ext_mic.pin);
Takashi Iwai6c819492009-08-10 18:47:44 +02001247
1248 /* FIXME: analog mixer */
Kailang Yang7fb0d782008-10-15 11:12:35 +02001249}
1250
Kailang Yangc9b58002007-10-16 14:30:01 +02001251/* unsolicited event for HP jack sensing */
1252static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
1253{
1254 if (codec->vendor_id == 0x10ec0880)
1255 res >>= 28;
1256 else
1257 res >>= 26;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001258 switch (res) {
1259 case ALC880_HP_EVENT:
1260 alc_automute_pin(codec);
1261 break;
1262 case ALC880_MIC_EVENT:
Kailang Yang7fb0d782008-10-15 11:12:35 +02001263 alc_mic_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001264 break;
1265 }
Kailang Yang7fb0d782008-10-15 11:12:35 +02001266}
1267
1268static void alc_inithook(struct hda_codec *codec)
1269{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001270 alc_automute_pin(codec);
Kailang Yang7fb0d782008-10-15 11:12:35 +02001271 alc_mic_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +02001272}
1273
Kailang Yangf9423e72008-05-27 12:32:25 +02001274/* additional initialization for ALC888 variants */
1275static void alc888_coef_init(struct hda_codec *codec)
1276{
1277 unsigned int tmp;
1278
1279 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
1280 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
1281 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
Takashi Iwai37db6232009-03-05 09:40:16 +01001282 if ((tmp & 0xf0) == 0x20)
Kailang Yangf9423e72008-05-27 12:32:25 +02001283 /* alc888S-VC */
1284 snd_hda_codec_read(codec, 0x20, 0,
1285 AC_VERB_SET_PROC_COEF, 0x830);
1286 else
1287 /* alc888-VB */
1288 snd_hda_codec_read(codec, 0x20, 0,
1289 AC_VERB_SET_PROC_COEF, 0x3030);
1290}
1291
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02001292static void alc889_coef_init(struct hda_codec *codec)
1293{
1294 unsigned int tmp;
1295
1296 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
1297 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
1298 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
1299 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, tmp|0x2010);
1300}
1301
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001302/* turn on/off EAPD control (only if available) */
1303static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on)
1304{
1305 if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
1306 return;
1307 if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
1308 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
1309 on ? 2 : 0);
1310}
1311
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001312static void alc_auto_init_amp(struct hda_codec *codec, int type)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001313{
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001314 unsigned int tmp;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001315
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001316 switch (type) {
1317 case ALC_INIT_GPIO1:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001318 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
1319 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001320 case ALC_INIT_GPIO2:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001321 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
1322 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001323 case ALC_INIT_GPIO3:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001324 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
1325 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001326 case ALC_INIT_DEFAULT:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001327 switch (codec->vendor_id) {
Kailang Yangc9b58002007-10-16 14:30:01 +02001328 case 0x10ec0260:
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001329 set_eapd(codec, 0x0f, 1);
1330 set_eapd(codec, 0x10, 1);
Kailang Yangc9b58002007-10-16 14:30:01 +02001331 break;
1332 case 0x10ec0262:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001333 case 0x10ec0267:
1334 case 0x10ec0268:
Kailang Yangc9b58002007-10-16 14:30:01 +02001335 case 0x10ec0269:
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001336 case 0x10ec0270:
Takashi Iwaic6e8f2d2009-02-06 12:45:52 +01001337 case 0x10ec0272:
Kailang Yangf9423e72008-05-27 12:32:25 +02001338 case 0x10ec0660:
1339 case 0x10ec0662:
1340 case 0x10ec0663:
Kailang Yangc9b58002007-10-16 14:30:01 +02001341 case 0x10ec0862:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001342 case 0x10ec0889:
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001343 set_eapd(codec, 0x14, 1);
1344 set_eapd(codec, 0x15, 1);
Kailang Yangc9b58002007-10-16 14:30:01 +02001345 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +02001346 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001347 switch (codec->vendor_id) {
1348 case 0x10ec0260:
1349 snd_hda_codec_write(codec, 0x1a, 0,
1350 AC_VERB_SET_COEF_INDEX, 7);
1351 tmp = snd_hda_codec_read(codec, 0x1a, 0,
1352 AC_VERB_GET_PROC_COEF, 0);
1353 snd_hda_codec_write(codec, 0x1a, 0,
1354 AC_VERB_SET_COEF_INDEX, 7);
1355 snd_hda_codec_write(codec, 0x1a, 0,
1356 AC_VERB_SET_PROC_COEF,
1357 tmp | 0x2010);
1358 break;
1359 case 0x10ec0262:
1360 case 0x10ec0880:
1361 case 0x10ec0882:
1362 case 0x10ec0883:
1363 case 0x10ec0885:
Takashi Iwai4a5a4c52009-02-06 12:46:59 +01001364 case 0x10ec0887:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001365 case 0x10ec0889:
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02001366 alc889_coef_init(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +02001367 break;
Kailang Yangf9423e72008-05-27 12:32:25 +02001368 case 0x10ec0888:
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001369 alc888_coef_init(codec);
Kailang Yangf9423e72008-05-27 12:32:25 +02001370 break;
Takashi Iwai0aea7782010-01-25 15:44:11 +01001371#if 0 /* XXX: This may cause the silent output on speaker on some machines */
Kailang Yangc9b58002007-10-16 14:30:01 +02001372 case 0x10ec0267:
1373 case 0x10ec0268:
1374 snd_hda_codec_write(codec, 0x20, 0,
1375 AC_VERB_SET_COEF_INDEX, 7);
1376 tmp = snd_hda_codec_read(codec, 0x20, 0,
1377 AC_VERB_GET_PROC_COEF, 0);
1378 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001379 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001380 snd_hda_codec_write(codec, 0x20, 0,
1381 AC_VERB_SET_PROC_COEF,
1382 tmp | 0x3000);
1383 break;
Takashi Iwai0aea7782010-01-25 15:44:11 +01001384#endif /* XXX */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001385 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001386 break;
1387 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001388}
Kailang Yangea1fb292008-08-26 12:58:38 +02001389
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001390static void alc_init_auto_hp(struct hda_codec *codec)
1391{
1392 struct alc_spec *spec = codec->spec;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001393 struct auto_pin_cfg *cfg = &spec->autocfg;
1394 int i;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001395
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001396 if (!cfg->hp_pins[0]) {
1397 if (cfg->line_out_type != AUTO_PIN_HP_OUT)
Kailang Yangc9b58002007-10-16 14:30:01 +02001398 return;
1399 }
1400
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001401 if (!cfg->speaker_pins[0]) {
1402 if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
1403 return;
1404 memcpy(cfg->speaker_pins, cfg->line_out_pins,
1405 sizeof(cfg->speaker_pins));
1406 cfg->speaker_outs = cfg->line_outs;
1407 }
1408
1409 if (!cfg->hp_pins[0]) {
1410 memcpy(cfg->hp_pins, cfg->line_out_pins,
1411 sizeof(cfg->hp_pins));
1412 cfg->hp_outs = cfg->line_outs;
1413 }
1414
1415 for (i = 0; i < cfg->hp_outs; i++) {
1416 snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
1417 cfg->hp_pins[i]);
1418 snd_hda_codec_write_cache(codec, cfg->hp_pins[i], 0,
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001419 AC_VERB_SET_UNSOLICITED_ENABLE,
1420 AC_USRSP_EN | ALC880_HP_EVENT);
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001421 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001422 spec->unsol_event = alc_sku_unsol_event;
1423}
1424
Takashi Iwai6c819492009-08-10 18:47:44 +02001425static void alc_init_auto_mic(struct hda_codec *codec)
1426{
1427 struct alc_spec *spec = codec->spec;
1428 struct auto_pin_cfg *cfg = &spec->autocfg;
1429 hda_nid_t fixed, ext;
1430 int i;
1431
1432 /* there must be only two mic inputs exclusively */
Takashi Iwai66ceeb62010-08-30 13:05:52 +02001433 for (i = 0; i < cfg->num_inputs; i++)
Takashi Iwai86e29592010-09-09 14:50:17 +02001434 if (cfg->inputs[i].type >= AUTO_PIN_LINE_IN)
Takashi Iwai6c819492009-08-10 18:47:44 +02001435 return;
1436
1437 fixed = ext = 0;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02001438 for (i = 0; i < cfg->num_inputs; i++) {
1439 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai6c819492009-08-10 18:47:44 +02001440 unsigned int defcfg;
Takashi Iwai6c819492009-08-10 18:47:44 +02001441 defcfg = snd_hda_codec_get_pincfg(codec, nid);
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001442 switch (snd_hda_get_input_pin_attr(defcfg)) {
1443 case INPUT_PIN_ATTR_INT:
Takashi Iwai6c819492009-08-10 18:47:44 +02001444 if (fixed)
1445 return; /* already occupied */
1446 fixed = nid;
1447 break;
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001448 case INPUT_PIN_ATTR_UNUSED:
1449 return; /* invalid entry */
1450 default:
Takashi Iwai6c819492009-08-10 18:47:44 +02001451 if (ext)
1452 return; /* already occupied */
1453 ext = nid;
1454 break;
Takashi Iwai6c819492009-08-10 18:47:44 +02001455 }
1456 }
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01001457 if (!ext || !fixed)
1458 return;
Takashi Iwai6c819492009-08-10 18:47:44 +02001459 if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP))
1460 return; /* no unsol support */
1461 snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x\n",
1462 ext, fixed);
1463 spec->ext_mic.pin = ext;
1464 spec->int_mic.pin = fixed;
1465 spec->ext_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
1466 spec->int_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
1467 spec->auto_mic = 1;
1468 snd_hda_codec_write_cache(codec, spec->ext_mic.pin, 0,
1469 AC_VERB_SET_UNSOLICITED_ENABLE,
1470 AC_USRSP_EN | ALC880_MIC_EVENT);
1471 spec->unsol_event = alc_sku_unsol_event;
1472}
1473
David Henningsson90622912010-10-14 14:50:18 +02001474/* Could be any non-zero and even value. When used as fixup, tells
1475 * the driver to ignore any present sku defines.
1476 */
1477#define ALC_FIXUP_SKU_IGNORE (2)
1478
Kailang Yangda00c242010-03-19 11:23:45 +01001479static int alc_auto_parse_customize_define(struct hda_codec *codec)
1480{
1481 unsigned int ass, tmp, i;
Takashi Iwai7fb56222010-03-22 17:09:47 +01001482 unsigned nid = 0;
Kailang Yangda00c242010-03-19 11:23:45 +01001483 struct alc_spec *spec = codec->spec;
1484
Takashi Iwaib6cbe512010-07-28 17:43:36 +02001485 spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
1486
David Henningsson90622912010-10-14 14:50:18 +02001487 if (spec->cdefine.fixup) {
1488 ass = spec->cdefine.sku_cfg;
1489 if (ass == ALC_FIXUP_SKU_IGNORE)
1490 return -1;
1491 goto do_sku;
1492 }
1493
Kailang Yangda00c242010-03-19 11:23:45 +01001494 ass = codec->subsystem_id & 0xffff;
Takashi Iwaib6cbe512010-07-28 17:43:36 +02001495 if (ass != codec->bus->pci->subsystem_device && (ass & 1))
Kailang Yangda00c242010-03-19 11:23:45 +01001496 goto do_sku;
1497
1498 nid = 0x1d;
1499 if (codec->vendor_id == 0x10ec0260)
1500 nid = 0x17;
1501 ass = snd_hda_codec_get_pincfg(codec, nid);
1502
1503 if (!(ass & 1)) {
1504 printk(KERN_INFO "hda_codec: %s: SKU not ready 0x%08x\n",
1505 codec->chip_name, ass);
1506 return -1;
1507 }
1508
1509 /* check sum */
1510 tmp = 0;
1511 for (i = 1; i < 16; i++) {
1512 if ((ass >> i) & 1)
1513 tmp++;
1514 }
1515 if (((ass >> 16) & 0xf) != tmp)
1516 return -1;
1517
1518 spec->cdefine.port_connectivity = ass >> 30;
1519 spec->cdefine.enable_pcbeep = (ass & 0x100000) >> 20;
1520 spec->cdefine.check_sum = (ass >> 16) & 0xf;
1521 spec->cdefine.customization = ass >> 8;
1522do_sku:
1523 spec->cdefine.sku_cfg = ass;
1524 spec->cdefine.external_amp = (ass & 0x38) >> 3;
1525 spec->cdefine.platform_type = (ass & 0x4) >> 2;
1526 spec->cdefine.swap = (ass & 0x2) >> 1;
1527 spec->cdefine.override = ass & 0x1;
1528
1529 snd_printd("SKU: Nid=0x%x sku_cfg=0x%08x\n",
1530 nid, spec->cdefine.sku_cfg);
1531 snd_printd("SKU: port_connectivity=0x%x\n",
1532 spec->cdefine.port_connectivity);
1533 snd_printd("SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep);
1534 snd_printd("SKU: check_sum=0x%08x\n", spec->cdefine.check_sum);
1535 snd_printd("SKU: customization=0x%08x\n", spec->cdefine.customization);
1536 snd_printd("SKU: external_amp=0x%x\n", spec->cdefine.external_amp);
1537 snd_printd("SKU: platform_type=0x%x\n", spec->cdefine.platform_type);
1538 snd_printd("SKU: swap=0x%x\n", spec->cdefine.swap);
1539 snd_printd("SKU: override=0x%x\n", spec->cdefine.override);
1540
1541 return 0;
1542}
1543
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001544/* check subsystem ID and set up device-specific initialization;
1545 * return 1 if initialized, 0 if invalid SSID
1546 */
1547/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
1548 * 31 ~ 16 : Manufacture ID
1549 * 15 ~ 8 : SKU ID
1550 * 7 ~ 0 : Assembly ID
1551 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
1552 */
1553static int alc_subsystem_id(struct hda_codec *codec,
1554 hda_nid_t porta, hda_nid_t porte,
Kailang Yang6227cdc2010-02-25 08:36:52 +01001555 hda_nid_t portd, hda_nid_t porti)
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001556{
1557 unsigned int ass, tmp, i;
1558 unsigned nid;
1559 struct alc_spec *spec = codec->spec;
1560
David Henningsson90622912010-10-14 14:50:18 +02001561 if (spec->cdefine.fixup) {
1562 ass = spec->cdefine.sku_cfg;
1563 if (ass == ALC_FIXUP_SKU_IGNORE)
1564 return 0;
1565 goto do_sku;
1566 }
1567
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001568 ass = codec->subsystem_id & 0xffff;
1569 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
1570 goto do_sku;
1571
1572 /* invalid SSID, check the special NID pin defcfg instead */
1573 /*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04001574 * 31~30 : port connectivity
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001575 * 29~21 : reserve
1576 * 20 : PCBEEP input
1577 * 19~16 : Check sum (15:1)
1578 * 15~1 : Custom
1579 * 0 : override
1580 */
1581 nid = 0x1d;
1582 if (codec->vendor_id == 0x10ec0260)
1583 nid = 0x17;
1584 ass = snd_hda_codec_get_pincfg(codec, nid);
1585 snd_printd("realtek: No valid SSID, "
1586 "checking pincfg 0x%08x for NID 0x%x\n",
Takashi Iwaicb6605c2009-04-28 13:03:19 +02001587 ass, nid);
Kailang Yang6227cdc2010-02-25 08:36:52 +01001588 if (!(ass & 1))
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001589 return 0;
1590 if ((ass >> 30) != 1) /* no physical connection */
1591 return 0;
1592
1593 /* check sum */
1594 tmp = 0;
1595 for (i = 1; i < 16; i++) {
1596 if ((ass >> i) & 1)
1597 tmp++;
1598 }
1599 if (((ass >> 16) & 0xf) != tmp)
1600 return 0;
1601do_sku:
1602 snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
1603 ass & 0xffff, codec->vendor_id);
1604 /*
1605 * 0 : override
1606 * 1 : Swap Jack
1607 * 2 : 0 --> Desktop, 1 --> Laptop
1608 * 3~5 : External Amplifier control
1609 * 7~6 : Reserved
1610 */
1611 tmp = (ass & 0x38) >> 3; /* external Amp control */
1612 switch (tmp) {
1613 case 1:
1614 spec->init_amp = ALC_INIT_GPIO1;
1615 break;
1616 case 3:
1617 spec->init_amp = ALC_INIT_GPIO2;
1618 break;
1619 case 7:
1620 spec->init_amp = ALC_INIT_GPIO3;
1621 break;
1622 case 5:
Takashi Iwai5a8cfb42010-11-26 17:11:18 +01001623 default:
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001624 spec->init_amp = ALC_INIT_DEFAULT;
1625 break;
1626 }
1627
1628 /* is laptop or Desktop and enable the function "Mute internal speaker
1629 * when the external headphone out jack is plugged"
1630 */
1631 if (!(ass & 0x8000))
1632 return 1;
1633 /*
1634 * 10~8 : Jack location
1635 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
1636 * 14~13: Resvered
1637 * 15 : 1 --> enable the function "Mute internal speaker
1638 * when the external headphone out jack is plugged"
1639 */
Kailang Yangc9b58002007-10-16 14:30:01 +02001640 if (!spec->autocfg.hp_pins[0]) {
Takashi Iwai01d48252009-10-06 13:21:54 +02001641 hda_nid_t nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001642 tmp = (ass >> 11) & 0x3; /* HP to chassis */
1643 if (tmp == 0)
Takashi Iwai01d48252009-10-06 13:21:54 +02001644 nid = porta;
Kailang Yangc9b58002007-10-16 14:30:01 +02001645 else if (tmp == 1)
Takashi Iwai01d48252009-10-06 13:21:54 +02001646 nid = porte;
Kailang Yangc9b58002007-10-16 14:30:01 +02001647 else if (tmp == 2)
Takashi Iwai01d48252009-10-06 13:21:54 +02001648 nid = portd;
Kailang Yang6227cdc2010-02-25 08:36:52 +01001649 else if (tmp == 3)
1650 nid = porti;
Kailang Yangc9b58002007-10-16 14:30:01 +02001651 else
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001652 return 1;
Takashi Iwai01d48252009-10-06 13:21:54 +02001653 for (i = 0; i < spec->autocfg.line_outs; i++)
1654 if (spec->autocfg.line_out_pins[i] == nid)
1655 return 1;
1656 spec->autocfg.hp_pins[0] = nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001657 }
1658
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001659 alc_init_auto_hp(codec);
Takashi Iwai6c819492009-08-10 18:47:44 +02001660 alc_init_auto_mic(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001661 return 1;
1662}
Kailang Yangea1fb292008-08-26 12:58:38 +02001663
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001664static void alc_ssid_check(struct hda_codec *codec,
Kailang Yang6227cdc2010-02-25 08:36:52 +01001665 hda_nid_t porta, hda_nid_t porte,
1666 hda_nid_t portd, hda_nid_t porti)
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001667{
Kailang Yang6227cdc2010-02-25 08:36:52 +01001668 if (!alc_subsystem_id(codec, porta, porte, portd, porti)) {
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001669 struct alc_spec *spec = codec->spec;
1670 snd_printd("realtek: "
1671 "Enable default setup for auto mode as fallback\n");
1672 spec->init_amp = ALC_INIT_DEFAULT;
1673 alc_init_auto_hp(codec);
Takashi Iwai6c819492009-08-10 18:47:44 +02001674 alc_init_auto_mic(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001675 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001676}
1677
Takashi Iwai41e41f12005-06-08 14:48:49 +02001678/*
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001679 * Fix-up pin default configurations and add default verbs
Takashi Iwaif95474e2007-07-10 00:47:43 +02001680 */
1681
1682struct alc_pincfg {
1683 hda_nid_t nid;
1684 u32 val;
1685};
1686
Todd Broche1eb5f12010-12-06 11:19:51 -08001687struct alc_model_fixup {
1688 const int id;
1689 const char *name;
1690};
1691
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001692struct alc_fixup {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001693 int type;
Takashi Iwai361fe6e2011-01-14 09:55:32 +01001694 bool chained;
1695 int chain_id;
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001696 union {
1697 unsigned int sku;
1698 const struct alc_pincfg *pins;
1699 const struct hda_verb *verbs;
1700 void (*func)(struct hda_codec *codec,
1701 const struct alc_fixup *fix,
1702 int action);
1703 } v;
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001704};
1705
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001706enum {
1707 ALC_FIXUP_INVALID,
1708 ALC_FIXUP_SKU,
1709 ALC_FIXUP_PINS,
1710 ALC_FIXUP_VERBS,
1711 ALC_FIXUP_FUNC,
1712};
Takashi Iwaif95474e2007-07-10 00:47:43 +02001713
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001714enum {
1715 ALC_FIXUP_ACT_PRE_PROBE,
1716 ALC_FIXUP_ACT_PROBE,
Takashi Iwai58701122011-01-13 15:41:45 +01001717 ALC_FIXUP_ACT_INIT,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001718};
1719
1720static void alc_apply_fixup(struct hda_codec *codec, int action)
1721{
1722 struct alc_spec *spec = codec->spec;
1723 int id = spec->fixup_id;
Takashi Iwaiaa1d0c52011-01-19 17:27:58 +01001724#ifdef CONFIG_SND_DEBUG_VERBOSE
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001725 const char *modelname = spec->fixup_name;
Takashi Iwaiaa1d0c52011-01-19 17:27:58 +01001726#endif
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001727 int depth = 0;
1728
1729 if (!spec->fixup_list)
1730 return;
1731
1732 while (id >= 0) {
1733 const struct alc_fixup *fix = spec->fixup_list + id;
1734 const struct alc_pincfg *cfg;
1735
1736 switch (fix->type) {
1737 case ALC_FIXUP_SKU:
1738 if (action != ALC_FIXUP_ACT_PRE_PROBE || !fix->v.sku)
1739 break;;
1740 snd_printdd(KERN_INFO "hda_codec: %s: "
1741 "Apply sku override for %s\n",
1742 codec->chip_name, modelname);
1743 spec->cdefine.sku_cfg = fix->v.sku;
1744 spec->cdefine.fixup = 1;
1745 break;
1746 case ALC_FIXUP_PINS:
1747 cfg = fix->v.pins;
1748 if (action != ALC_FIXUP_ACT_PRE_PROBE || !cfg)
1749 break;
1750 snd_printdd(KERN_INFO "hda_codec: %s: "
1751 "Apply pincfg for %s\n",
1752 codec->chip_name, modelname);
1753 for (; cfg->nid; cfg++)
1754 snd_hda_codec_set_pincfg(codec, cfg->nid,
1755 cfg->val);
1756 break;
1757 case ALC_FIXUP_VERBS:
1758 if (action != ALC_FIXUP_ACT_PROBE || !fix->v.verbs)
1759 break;
1760 snd_printdd(KERN_INFO "hda_codec: %s: "
1761 "Apply fix-verbs for %s\n",
1762 codec->chip_name, modelname);
1763 add_verb(codec->spec, fix->v.verbs);
1764 break;
1765 case ALC_FIXUP_FUNC:
1766 if (!fix->v.func)
1767 break;
1768 snd_printdd(KERN_INFO "hda_codec: %s: "
1769 "Apply fix-func for %s\n",
1770 codec->chip_name, modelname);
1771 fix->v.func(codec, fix, action);
1772 break;
1773 default:
1774 snd_printk(KERN_ERR "hda_codec: %s: "
1775 "Invalid fixup type %d\n",
1776 codec->chip_name, fix->type);
1777 break;
1778 }
1779 if (!fix[id].chained)
1780 break;
1781 if (++depth > 10)
1782 break;
1783 id = fix[id].chain_id;
Takashi Iwai9d578832010-11-22 13:29:19 +01001784 }
Takashi Iwaif95474e2007-07-10 00:47:43 +02001785}
1786
Todd Broche1eb5f12010-12-06 11:19:51 -08001787static void alc_pick_fixup(struct hda_codec *codec,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001788 const struct alc_model_fixup *models,
1789 const struct snd_pci_quirk *quirk,
1790 const struct alc_fixup *fixlist)
Todd Broche1eb5f12010-12-06 11:19:51 -08001791{
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001792 struct alc_spec *spec = codec->spec;
1793 int id = -1;
1794 const char *name = NULL;
Todd Broche1eb5f12010-12-06 11:19:51 -08001795
Todd Broche1eb5f12010-12-06 11:19:51 -08001796 if (codec->modelname && models) {
1797 while (models->name) {
1798 if (!strcmp(codec->modelname, models->name)) {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001799 id = models->id;
1800 name = models->name;
Todd Broche1eb5f12010-12-06 11:19:51 -08001801 break;
1802 }
1803 models++;
1804 }
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001805 }
1806 if (id < 0) {
1807 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
1808 if (quirk) {
1809 id = quirk->value;
1810#ifdef CONFIG_SND_DEBUG_VERBOSE
1811 name = quirk->name;
1812#endif
1813 }
1814 }
1815
1816 spec->fixup_id = id;
1817 if (id >= 0) {
1818 spec->fixup_list = fixlist;
1819 spec->fixup_name = name;
Todd Broche1eb5f12010-12-06 11:19:51 -08001820 }
Takashi Iwaif95474e2007-07-10 00:47:43 +02001821}
1822
Kailang Yang274693f2009-12-03 10:07:50 +01001823static int alc_read_coef_idx(struct hda_codec *codec,
1824 unsigned int coef_idx)
1825{
1826 unsigned int val;
1827 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
1828 coef_idx);
1829 val = snd_hda_codec_read(codec, 0x20, 0,
1830 AC_VERB_GET_PROC_COEF, 0);
1831 return val;
1832}
1833
Kailang Yang977ddd62010-09-15 10:02:29 +02001834static void alc_write_coef_idx(struct hda_codec *codec, unsigned int coef_idx,
1835 unsigned int coef_val)
1836{
1837 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
1838 coef_idx);
1839 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF,
1840 coef_val);
1841}
1842
Takashi Iwai757899a2010-07-30 10:48:14 +02001843/* set right pin controls for digital I/O */
1844static void alc_auto_init_digital(struct hda_codec *codec)
1845{
1846 struct alc_spec *spec = codec->spec;
1847 int i;
1848 hda_nid_t pin;
1849
1850 for (i = 0; i < spec->autocfg.dig_outs; i++) {
1851 pin = spec->autocfg.dig_out_pins[i];
1852 if (pin) {
1853 snd_hda_codec_write(codec, pin, 0,
1854 AC_VERB_SET_PIN_WIDGET_CONTROL,
1855 PIN_OUT);
1856 }
1857 }
1858 pin = spec->autocfg.dig_in_pin;
1859 if (pin)
1860 snd_hda_codec_write(codec, pin, 0,
1861 AC_VERB_SET_PIN_WIDGET_CONTROL,
1862 PIN_IN);
1863}
1864
1865/* parse digital I/Os and set up NIDs in BIOS auto-parse mode */
1866static void alc_auto_parse_digital(struct hda_codec *codec)
1867{
1868 struct alc_spec *spec = codec->spec;
1869 int i, err;
1870 hda_nid_t dig_nid;
1871
1872 /* support multiple SPDIFs; the secondary is set up as a slave */
1873 for (i = 0; i < spec->autocfg.dig_outs; i++) {
1874 err = snd_hda_get_connections(codec,
1875 spec->autocfg.dig_out_pins[i],
1876 &dig_nid, 1);
1877 if (err < 0)
1878 continue;
1879 if (!i) {
1880 spec->multiout.dig_out_nid = dig_nid;
1881 spec->dig_out_type = spec->autocfg.dig_out_type[0];
1882 } else {
1883 spec->multiout.slave_dig_outs = spec->slave_dig_outs;
1884 if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
1885 break;
1886 spec->slave_dig_outs[i - 1] = dig_nid;
1887 }
1888 }
1889
1890 if (spec->autocfg.dig_in_pin) {
Takashi Iwai01fdf182010-09-24 09:09:42 +02001891 dig_nid = codec->start_nid;
1892 for (i = 0; i < codec->num_nodes; i++, dig_nid++) {
1893 unsigned int wcaps = get_wcaps(codec, dig_nid);
1894 if (get_wcaps_type(wcaps) != AC_WID_AUD_IN)
1895 continue;
1896 if (!(wcaps & AC_WCAP_DIGITAL))
1897 continue;
1898 if (!(wcaps & AC_WCAP_CONN_LIST))
1899 continue;
1900 err = get_connection_index(codec, dig_nid,
1901 spec->autocfg.dig_in_pin);
1902 if (err >= 0) {
1903 spec->dig_in_nid = dig_nid;
1904 break;
1905 }
1906 }
Takashi Iwai757899a2010-07-30 10:48:14 +02001907 }
1908}
1909
Takashi Iwaif95474e2007-07-10 00:47:43 +02001910/*
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001911 * ALC888
1912 */
1913
1914/*
1915 * 2ch mode
1916 */
1917static struct hda_verb alc888_4ST_ch2_intel_init[] = {
1918/* Mic-in jack as mic in */
1919 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1920 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1921/* Line-in jack as Line in */
1922 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1923 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1924/* Line-Out as Front */
1925 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
1926 { } /* end */
1927};
1928
1929/*
1930 * 4ch mode
1931 */
1932static struct hda_verb alc888_4ST_ch4_intel_init[] = {
1933/* Mic-in jack as mic in */
1934 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1935 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1936/* Line-in jack as Surround */
1937 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1938 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1939/* Line-Out as Front */
1940 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
1941 { } /* end */
1942};
1943
1944/*
1945 * 6ch mode
1946 */
1947static struct hda_verb alc888_4ST_ch6_intel_init[] = {
1948/* Mic-in jack as CLFE */
1949 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1950 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1951/* Line-in jack as Surround */
1952 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1953 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1954/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */
1955 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1956 { } /* end */
1957};
1958
1959/*
1960 * 8ch mode
1961 */
1962static struct hda_verb alc888_4ST_ch8_intel_init[] = {
1963/* Mic-in jack as CLFE */
1964 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1965 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1966/* Line-in jack as Surround */
1967 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1968 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1969/* Line-Out as Side */
1970 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1971 { } /* end */
1972};
1973
1974static struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
1975 { 2, alc888_4ST_ch2_intel_init },
1976 { 4, alc888_4ST_ch4_intel_init },
1977 { 6, alc888_4ST_ch6_intel_init },
1978 { 8, alc888_4ST_ch8_intel_init },
1979};
1980
1981/*
1982 * ALC888 Fujitsu Siemens Amillo xa3530
1983 */
1984
1985static struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
1986/* Front Mic: set to PIN_IN (empty by default) */
1987 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1988/* Connect Internal HP to Front */
1989 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1990 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1991 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1992/* Connect Bass HP to Front */
1993 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1994 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1995 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1996/* Connect Line-Out side jack (SPDIF) to Side */
1997 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1998 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1999 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
2000/* Connect Mic jack to CLFE */
2001 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2002 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2003 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
2004/* Connect Line-in jack to Surround */
2005 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2006 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2007 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
2008/* Connect HP out jack to Front */
2009 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2010 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2011 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
2012/* Enable unsolicited event for HP jack and Line-out jack */
2013 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2014 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2015 {}
2016};
2017
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002018static void alc_automute_amp(struct hda_codec *codec)
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002019{
Takashi Iwaibb35feb2010-09-08 15:30:49 +02002020 alc_automute_speaker(codec, 0);
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002021}
2022
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002023static void alc_automute_amp_unsol_event(struct hda_codec *codec,
2024 unsigned int res)
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002025{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002026 if (codec->vendor_id == 0x10ec0880)
2027 res >>= 28;
2028 else
2029 res >>= 26;
2030 if (res == ALC880_HP_EVENT)
2031 alc_automute_amp(codec);
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002032}
2033
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002034static void alc889_automute_setup(struct hda_codec *codec)
Wu Fengguang6732bd02009-07-30 09:19:14 +02002035{
2036 struct alc_spec *spec = codec->spec;
2037
2038 spec->autocfg.hp_pins[0] = 0x15;
2039 spec->autocfg.speaker_pins[0] = 0x14;
2040 spec->autocfg.speaker_pins[1] = 0x16;
2041 spec->autocfg.speaker_pins[2] = 0x17;
2042 spec->autocfg.speaker_pins[3] = 0x19;
2043 spec->autocfg.speaker_pins[4] = 0x1a;
Wu Fengguang6732bd02009-07-30 09:19:14 +02002044}
2045
2046static void alc889_intel_init_hook(struct hda_codec *codec)
2047{
2048 alc889_coef_init(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002049 alc_automute_amp(codec);
Wu Fengguang6732bd02009-07-30 09:19:14 +02002050}
2051
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002052static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002053{
2054 struct alc_spec *spec = codec->spec;
2055
2056 spec->autocfg.hp_pins[0] = 0x17; /* line-out */
2057 spec->autocfg.hp_pins[1] = 0x1b; /* hp */
2058 spec->autocfg.speaker_pins[0] = 0x14; /* speaker */
2059 spec->autocfg.speaker_pins[1] = 0x15; /* bass */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002060}
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002061
2062/*
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002063 * ALC888 Acer Aspire 4930G model
2064 */
2065
2066static struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
2067/* Front Mic: set to PIN_IN (empty by default) */
2068 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2069/* Unselect Front Mic by default in input mixer 3 */
2070 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002071/* Enable unsolicited event for HP jack */
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002072 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2073/* Connect Internal HP to front */
2074 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2075 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2076 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
2077/* Connect HP out to front */
2078 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2079 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2080 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie2e93292011-01-12 08:03:39 +01002081 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002082 { }
2083};
2084
Hector Martin3b315d72009-06-02 10:54:19 +02002085/*
Tony Vroond2fd4b02009-06-21 00:40:10 +01002086 * ALC888 Acer Aspire 6530G model
2087 */
2088
2089static struct hda_verb alc888_acer_aspire_6530g_verbs[] = {
Tony Vroond1284182010-04-05 16:30:43 +01002090/* Route to built-in subwoofer as well as speakers */
2091 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2092 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2093 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2094 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Tony Vroond2fd4b02009-06-21 00:40:10 +01002095/* Bias voltage on for external mic port */
2096 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
Emilio López320d5922009-06-25 08:18:44 +02002097/* Front Mic: set to PIN_IN (empty by default) */
2098 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2099/* Unselect Front Mic by default in input mixer 3 */
2100 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Tony Vroond2fd4b02009-06-21 00:40:10 +01002101/* Enable unsolicited event for HP jack */
2102 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2103/* Enable speaker output */
2104 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2105 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Tony Vroond1284182010-04-05 16:30:43 +01002106 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Tony Vroond2fd4b02009-06-21 00:40:10 +01002107/* Enable headphone output */
2108 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
2109 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2110 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Tony Vroond1284182010-04-05 16:30:43 +01002111 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
Tony Vroond2fd4b02009-06-21 00:40:10 +01002112 { }
2113};
2114
2115/*
Denis Kuplyakovd9477202010-11-24 06:01:09 +01002116 *ALC888 Acer Aspire 7730G model
2117 */
2118
2119static struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
2120/* Bias voltage on for external mic port */
2121 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
2122/* Front Mic: set to PIN_IN (empty by default) */
2123 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2124/* Unselect Front Mic by default in input mixer 3 */
2125 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
2126/* Enable unsolicited event for HP jack */
2127 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2128/* Enable speaker output */
2129 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2130 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2131 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
2132/* Enable headphone output */
2133 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
2134 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2135 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
2136 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
2137/*Enable internal subwoofer */
2138 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2139 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2140 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
2141 {0x17, AC_VERB_SET_EAPD_BTLENABLE, 2},
2142 { }
2143};
2144
2145/*
Hector Martin018df412009-06-04 00:13:40 +02002146 * ALC889 Acer Aspire 8930G model
Hector Martin3b315d72009-06-02 10:54:19 +02002147 */
2148
Hector Martin018df412009-06-04 00:13:40 +02002149static struct hda_verb alc889_acer_aspire_8930g_verbs[] = {
Hector Martin3b315d72009-06-02 10:54:19 +02002150/* Front Mic: set to PIN_IN (empty by default) */
2151 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2152/* Unselect Front Mic by default in input mixer 3 */
2153 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
2154/* Enable unsolicited event for HP jack */
2155 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2156/* Connect Internal Front to Front */
2157 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2158 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2159 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
2160/* Connect Internal Rear to Rear */
2161 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2162 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2163 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
2164/* Connect Internal CLFE to CLFE */
2165 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2166 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2167 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
2168/* Connect HP out to Front */
Hector Martin018df412009-06-04 00:13:40 +02002169 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
Hector Martin3b315d72009-06-02 10:54:19 +02002170 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2171 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
2172/* Enable all DACs */
2173/* DAC DISABLE/MUTE 1? */
2174/* setting bits 1-5 disables DAC nids 0x02-0x06 apparently. Init=0x38 */
2175 {0x20, AC_VERB_SET_COEF_INDEX, 0x03},
2176 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
2177/* DAC DISABLE/MUTE 2? */
2178/* some bit here disables the other DACs. Init=0x4900 */
2179 {0x20, AC_VERB_SET_COEF_INDEX, 0x08},
2180 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
Hector Martin018df412009-06-04 00:13:40 +02002181/* DMIC fix
2182 * This laptop has a stereo digital microphone. The mics are only 1cm apart
2183 * which makes the stereo useless. However, either the mic or the ALC889
2184 * makes the signal become a difference/sum signal instead of standard
2185 * stereo, which is annoying. So instead we flip this bit which makes the
2186 * codec replicate the sum signal to both channels, turning it into a
2187 * normal mono mic.
2188 */
2189/* DMIC_CONTROL? Init value = 0x0001 */
2190 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
2191 {0x20, AC_VERB_SET_PROC_COEF, 0x0003},
Hector Martin3b315d72009-06-02 10:54:19 +02002192 { }
2193};
2194
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002195static struct hda_input_mux alc888_2_capture_sources[2] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002196 /* Front mic only available on one ADC */
2197 {
2198 .num_items = 4,
2199 .items = {
2200 { "Mic", 0x0 },
2201 { "Line", 0x2 },
2202 { "CD", 0x4 },
2203 { "Front Mic", 0xb },
2204 },
2205 },
2206 {
2207 .num_items = 3,
2208 .items = {
2209 { "Mic", 0x0 },
2210 { "Line", 0x2 },
2211 { "CD", 0x4 },
2212 },
2213 }
2214};
2215
Tony Vroond2fd4b02009-06-21 00:40:10 +01002216static struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
2217 /* Interal mic only available on one ADC */
2218 {
Tony Vroon684a8842009-06-26 09:27:50 +01002219 .num_items = 5,
Tony Vroond2fd4b02009-06-21 00:40:10 +01002220 .items = {
David Henningsson8607f7c2010-12-20 14:43:54 +01002221 { "Mic", 0x0 },
Tony Vroon684a8842009-06-26 09:27:50 +01002222 { "Line In", 0x2 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002223 { "CD", 0x4 },
Tony Vroon684a8842009-06-26 09:27:50 +01002224 { "Input Mix", 0xa },
David Henningsson28c4edb2010-12-20 14:24:29 +01002225 { "Internal Mic", 0xb },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002226 },
2227 },
2228 {
Tony Vroon684a8842009-06-26 09:27:50 +01002229 .num_items = 4,
Tony Vroond2fd4b02009-06-21 00:40:10 +01002230 .items = {
David Henningsson8607f7c2010-12-20 14:43:54 +01002231 { "Mic", 0x0 },
Tony Vroon684a8842009-06-26 09:27:50 +01002232 { "Line In", 0x2 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002233 { "CD", 0x4 },
Tony Vroon684a8842009-06-26 09:27:50 +01002234 { "Input Mix", 0xa },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002235 },
2236 }
2237};
2238
Hector Martin018df412009-06-04 00:13:40 +02002239static struct hda_input_mux alc889_capture_sources[3] = {
2240 /* Digital mic only available on first "ADC" */
2241 {
2242 .num_items = 5,
2243 .items = {
2244 { "Mic", 0x0 },
2245 { "Line", 0x2 },
2246 { "CD", 0x4 },
2247 { "Front Mic", 0xb },
2248 { "Input Mix", 0xa },
2249 },
2250 },
2251 {
2252 .num_items = 4,
2253 .items = {
2254 { "Mic", 0x0 },
2255 { "Line", 0x2 },
2256 { "CD", 0x4 },
2257 { "Input Mix", 0xa },
2258 },
2259 },
2260 {
2261 .num_items = 4,
2262 .items = {
2263 { "Mic", 0x0 },
2264 { "Line", 0x2 },
2265 { "CD", 0x4 },
2266 { "Input Mix", 0xa },
2267 },
2268 }
2269};
2270
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002271static struct snd_kcontrol_new alc888_base_mixer[] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002272 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2273 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2274 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2275 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2276 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
2277 HDA_OUTPUT),
2278 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2279 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2280 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2281 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2282 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
2283 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2284 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2285 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2286 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2287 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01002288 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002289 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002290 { } /* end */
2291};
2292
Hector Martin556eea92009-12-20 22:51:23 +01002293static struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = {
2294 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2295 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2296 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2297 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2298 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
2299 HDA_OUTPUT),
2300 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2301 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2302 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2303 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2304 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2305 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01002306 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Hector Martin556eea92009-12-20 22:51:23 +01002307 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2308 { } /* end */
2309};
2310
2311
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002312static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec)
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002313{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002314 struct alc_spec *spec = codec->spec;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002315
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002316 spec->autocfg.hp_pins[0] = 0x15;
2317 spec->autocfg.speaker_pins[0] = 0x14;
Łukasz Wojniłowicz7cef4cf2009-11-20 12:14:35 +01002318 spec->autocfg.speaker_pins[1] = 0x16;
2319 spec->autocfg.speaker_pins[2] = 0x17;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002320}
2321
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002322static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec)
Emilio López320d5922009-06-25 08:18:44 +02002323{
2324 struct alc_spec *spec = codec->spec;
2325
2326 spec->autocfg.hp_pins[0] = 0x15;
2327 spec->autocfg.speaker_pins[0] = 0x14;
2328 spec->autocfg.speaker_pins[1] = 0x16;
2329 spec->autocfg.speaker_pins[2] = 0x17;
Emilio López320d5922009-06-25 08:18:44 +02002330}
2331
Denis Kuplyakovd9477202010-11-24 06:01:09 +01002332static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec)
2333{
2334 struct alc_spec *spec = codec->spec;
2335
2336 spec->autocfg.hp_pins[0] = 0x15;
2337 spec->autocfg.speaker_pins[0] = 0x14;
2338 spec->autocfg.speaker_pins[1] = 0x16;
2339 spec->autocfg.speaker_pins[2] = 0x17;
2340}
2341
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002342static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
Hector Martin3b315d72009-06-02 10:54:19 +02002343{
2344 struct alc_spec *spec = codec->spec;
2345
2346 spec->autocfg.hp_pins[0] = 0x15;
2347 spec->autocfg.speaker_pins[0] = 0x14;
2348 spec->autocfg.speaker_pins[1] = 0x16;
2349 spec->autocfg.speaker_pins[2] = 0x1b;
Hector Martin3b315d72009-06-02 10:54:19 +02002350}
2351
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002352/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002353 * ALC880 3-stack model
2354 *
2355 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002356 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
2357 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 */
2359
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002360static hda_nid_t alc880_dac_nids[4] = {
2361 /* front, rear, clfe, rear_surr */
2362 0x02, 0x05, 0x04, 0x03
2363};
2364
2365static hda_nid_t alc880_adc_nids[3] = {
2366 /* ADC0-2 */
2367 0x07, 0x08, 0x09,
2368};
2369
2370/* The datasheet says the node 0x07 is connected from inputs,
2371 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +01002372 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002374static hda_nid_t alc880_adc_nids_alt[2] = {
2375 /* ADC1-2 */
2376 0x08, 0x09,
2377};
2378
2379#define ALC880_DIGOUT_NID 0x06
2380#define ALC880_DIGIN_NID 0x0a
2381
2382static struct hda_input_mux alc880_capture_source = {
2383 .num_items = 4,
2384 .items = {
2385 { "Mic", 0x0 },
2386 { "Front Mic", 0x3 },
2387 { "Line", 0x2 },
2388 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002390};
2391
2392/* channel source setting (2/6 channel selection for 3-stack) */
2393/* 2ch mode */
2394static struct hda_verb alc880_threestack_ch2_init[] = {
2395 /* set line-in to input, mute it */
2396 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2397 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2398 /* set mic-in to input vref 80%, mute it */
2399 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2400 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 { } /* end */
2402};
2403
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002404/* 6ch mode */
2405static struct hda_verb alc880_threestack_ch6_init[] = {
2406 /* set line-in to output, unmute it */
2407 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2408 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2409 /* set mic-in to output, unmute it */
2410 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2411 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2412 { } /* end */
2413};
2414
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002415static struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002416 { 2, alc880_threestack_ch2_init },
2417 { 6, alc880_threestack_ch6_init },
2418};
2419
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002420static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002421 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002422 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02002423 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002424 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02002425 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2426 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002427 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2428 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2430 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2431 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2432 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2433 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2434 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2435 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
2436 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002438 {
2439 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2440 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002441 .info = alc_ch_mode_info,
2442 .get = alc_ch_mode_get,
2443 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002444 },
2445 { } /* end */
2446};
2447
2448/* capture mixer elements */
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002449static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
2450 struct snd_ctl_elem_info *uinfo)
2451{
2452 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2453 struct alc_spec *spec = codec->spec;
2454 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002455
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002456 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002457 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
2458 HDA_INPUT);
2459 err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002460 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002461 return err;
2462}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002464static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
2465 unsigned int size, unsigned int __user *tlv)
2466{
2467 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2468 struct alc_spec *spec = codec->spec;
2469 int err;
2470
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002471 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002472 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
2473 HDA_INPUT);
2474 err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002475 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002476 return err;
2477}
2478
2479typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
2480 struct snd_ctl_elem_value *ucontrol);
2481
2482static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
2483 struct snd_ctl_elem_value *ucontrol,
2484 getput_call_t func)
2485{
2486 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2487 struct alc_spec *spec = codec->spec;
2488 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
2489 int err;
2490
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002491 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002492 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[adc_idx],
2493 3, 0, HDA_INPUT);
2494 err = func(kcontrol, ucontrol);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002495 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002496 return err;
2497}
2498
2499static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
2500 struct snd_ctl_elem_value *ucontrol)
2501{
2502 return alc_cap_getput_caller(kcontrol, ucontrol,
2503 snd_hda_mixer_amp_volume_get);
2504}
2505
2506static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
2507 struct snd_ctl_elem_value *ucontrol)
2508{
2509 return alc_cap_getput_caller(kcontrol, ucontrol,
2510 snd_hda_mixer_amp_volume_put);
2511}
2512
2513/* capture mixer elements */
2514#define alc_cap_sw_info snd_ctl_boolean_stereo_info
2515
2516static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
2517 struct snd_ctl_elem_value *ucontrol)
2518{
2519 return alc_cap_getput_caller(kcontrol, ucontrol,
2520 snd_hda_mixer_amp_switch_get);
2521}
2522
2523static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
2524 struct snd_ctl_elem_value *ucontrol)
2525{
2526 return alc_cap_getput_caller(kcontrol, ucontrol,
2527 snd_hda_mixer_amp_switch_put);
2528}
2529
Takashi Iwaia23b6882009-03-23 15:21:36 +01002530#define _DEFINE_CAPMIX(num) \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002531 { \
2532 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2533 .name = "Capture Switch", \
2534 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
2535 .count = num, \
2536 .info = alc_cap_sw_info, \
2537 .get = alc_cap_sw_get, \
2538 .put = alc_cap_sw_put, \
2539 }, \
2540 { \
2541 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2542 .name = "Capture Volume", \
2543 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
2544 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
2545 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
2546 .count = num, \
2547 .info = alc_cap_vol_info, \
2548 .get = alc_cap_vol_get, \
2549 .put = alc_cap_vol_put, \
2550 .tlv = { .c = alc_cap_vol_tlv }, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002551 }
2552
2553#define _DEFINE_CAPSRC(num) \
Takashi Iwai3c3e9892008-10-31 17:48:56 +01002554 { \
2555 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2556 /* .name = "Capture Source", */ \
2557 .name = "Input Source", \
2558 .count = num, \
2559 .info = alc_mux_enum_info, \
2560 .get = alc_mux_enum_get, \
2561 .put = alc_mux_enum_put, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002562 }
2563
2564#define DEFINE_CAPMIX(num) \
2565static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
2566 _DEFINE_CAPMIX(num), \
2567 _DEFINE_CAPSRC(num), \
2568 { } /* end */ \
2569}
2570
2571#define DEFINE_CAPMIX_NOSRC(num) \
2572static struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
2573 _DEFINE_CAPMIX(num), \
2574 { } /* end */ \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002575}
2576
2577/* up to three ADCs */
2578DEFINE_CAPMIX(1);
2579DEFINE_CAPMIX(2);
2580DEFINE_CAPMIX(3);
Takashi Iwaia23b6882009-03-23 15:21:36 +01002581DEFINE_CAPMIX_NOSRC(1);
2582DEFINE_CAPMIX_NOSRC(2);
2583DEFINE_CAPMIX_NOSRC(3);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002584
2585/*
2586 * ALC880 5-stack model
2587 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002588 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
2589 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002590 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
2591 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
2592 */
2593
2594/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002595static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002596 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002597 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 { } /* end */
2599};
2600
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002601/* channel source setting (6/8 channel selection for 5-stack) */
2602/* 6ch mode */
2603static struct hda_verb alc880_fivestack_ch6_init[] = {
2604 /* set line-in to input, mute it */
2605 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2606 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002607 { } /* end */
2608};
2609
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002610/* 8ch mode */
2611static struct hda_verb alc880_fivestack_ch8_init[] = {
2612 /* set line-in to output, unmute it */
2613 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2614 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2615 { } /* end */
2616};
2617
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002618static struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002619 { 6, alc880_fivestack_ch6_init },
2620 { 8, alc880_fivestack_ch8_init },
2621};
2622
2623
2624/*
2625 * ALC880 6-stack model
2626 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002627 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
2628 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002629 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
2630 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
2631 */
2632
2633static hda_nid_t alc880_6st_dac_nids[4] = {
2634 /* front, rear, clfe, rear_surr */
2635 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002636};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002637
2638static struct hda_input_mux alc880_6stack_capture_source = {
2639 .num_items = 4,
2640 .items = {
2641 { "Mic", 0x0 },
2642 { "Front Mic", 0x1 },
2643 { "Line", 0x2 },
2644 { "CD", 0x4 },
2645 },
2646};
2647
2648/* fixed 8-channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002649static struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002650 { 8, NULL },
2651};
2652
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002653static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002654 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002655 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002656 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002657 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002658 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2659 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002660 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2661 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002662 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002663 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002664 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2665 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2666 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2667 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2668 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2669 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2670 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2671 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002672 {
2673 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2674 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002675 .info = alc_ch_mode_info,
2676 .get = alc_ch_mode_get,
2677 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02002678 },
2679 { } /* end */
2680};
2681
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002682
2683/*
2684 * ALC880 W810 model
2685 *
2686 * W810 has rear IO for:
2687 * Front (DAC 02)
2688 * Surround (DAC 03)
2689 * Center/LFE (DAC 04)
2690 * Digital out (06)
2691 *
2692 * The system also has a pair of internal speakers, and a headphone jack.
2693 * These are both connected to Line2 on the codec, hence to DAC 02.
Kailang Yangea1fb292008-08-26 12:58:38 +02002694 *
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002695 * There is a variable resistor to control the speaker or headphone
2696 * volume. This is a hardware-only device without a software API.
2697 *
2698 * Plugging headphones in will disable the internal speakers. This is
2699 * implemented in hardware, not via the driver using jack sense. In
2700 * a similar fashion, plugging into the rear socket marked "front" will
2701 * disable both the speakers and headphones.
2702 *
2703 * For input, there's a microphone jack, and an "audio in" jack.
2704 * These may not do anything useful with this driver yet, because I
2705 * haven't setup any initialization verbs for these yet...
2706 */
2707
2708static hda_nid_t alc880_w810_dac_nids[3] = {
2709 /* front, rear/surround, clfe */
2710 0x02, 0x03, 0x04
2711};
2712
2713/* fixed 6 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002714static struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002715 { 6, NULL }
2716};
2717
2718/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002719static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002720 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002721 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002722 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002723 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002724 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2725 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002726 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2727 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002728 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
2729 { } /* end */
2730};
2731
2732
2733/*
2734 * Z710V model
2735 *
2736 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002737 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
2738 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002739 */
2740
2741static hda_nid_t alc880_z71v_dac_nids[1] = {
2742 0x02
2743};
2744#define ALC880_Z71V_HP_DAC 0x03
2745
2746/* fixed 2 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002747static struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002748 { 2, NULL }
2749};
2750
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002751static struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002752 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002753 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002754 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002755 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002756 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2757 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2758 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2759 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2760 { } /* end */
2761};
2762
2763
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002764/*
2765 * ALC880 F1734 model
2766 *
2767 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
2768 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
2769 */
2770
2771static hda_nid_t alc880_f1734_dac_nids[1] = {
2772 0x03
2773};
2774#define ALC880_F1734_HP_DAC 0x02
2775
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002776static struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002777 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002778 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01002779 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2780 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002781 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2782 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01002783 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2784 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002785 { } /* end */
2786};
2787
Takashi Iwai937b4162008-02-11 14:52:36 +01002788static struct hda_input_mux alc880_f1734_capture_source = {
2789 .num_items = 2,
2790 .items = {
2791 { "Mic", 0x1 },
2792 { "CD", 0x4 },
2793 },
2794};
2795
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002796
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002797/*
2798 * ALC880 ASUS model
2799 *
2800 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
2801 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
2802 * Mic = 0x18, Line = 0x1a
2803 */
2804
2805#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
2806#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
2807
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002808static struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002809 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002810 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002811 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002812 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002813 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2814 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002815 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2816 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002817 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2818 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2819 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2820 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2821 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2822 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002823 {
2824 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2825 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002826 .info = alc_ch_mode_info,
2827 .get = alc_ch_mode_get,
2828 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02002829 },
2830 { } /* end */
2831};
2832
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002833/*
2834 * ALC880 ASUS W1V model
2835 *
2836 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
2837 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
2838 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
2839 */
2840
2841/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002842static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002843 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
2844 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002845 { } /* end */
2846};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002847
Kailang Yangdf694da2005-12-05 19:42:22 +01002848/* TCL S700 */
2849static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
2850 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2851 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
2852 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
2853 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
2854 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
2855 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
2856 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
2857 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
2858 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01002859 { } /* end */
2860};
2861
Kailang Yangccc656c2006-10-17 12:32:26 +02002862/* Uniwill */
2863static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002864 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2865 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2866 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2867 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002868 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2869 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2870 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2871 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2872 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2873 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2874 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2875 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2876 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2877 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2878 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2879 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002880 {
2881 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2882 .name = "Channel Mode",
2883 .info = alc_ch_mode_info,
2884 .get = alc_ch_mode_get,
2885 .put = alc_ch_mode_put,
2886 },
2887 { } /* end */
2888};
2889
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002890static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
2891 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2892 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2893 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2894 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
2895 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2896 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
David Henningsson8607f7c2010-12-20 14:43:54 +01002897 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2898 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01002899 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2900 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002901 { } /* end */
2902};
2903
Kailang Yangccc656c2006-10-17 12:32:26 +02002904static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002905 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2906 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2907 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2908 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002909 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2910 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2911 { } /* end */
2912};
2913
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01002915 * virtual master controls
2916 */
2917
2918/*
2919 * slave controls for virtual master
2920 */
Takashi Iwaiea734962011-01-17 11:29:34 +01002921static const char * const alc_slave_vols[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002922 "Front Playback Volume",
2923 "Surround Playback Volume",
2924 "Center Playback Volume",
2925 "LFE Playback Volume",
2926 "Side Playback Volume",
2927 "Headphone Playback Volume",
2928 "Speaker Playback Volume",
2929 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002930 "Line-Out Playback Volume",
Takashi Iwai26f5df22008-11-03 17:39:46 +01002931 "PCM Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002932 NULL,
2933};
2934
Takashi Iwaiea734962011-01-17 11:29:34 +01002935static const char * const alc_slave_sws[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002936 "Front Playback Switch",
2937 "Surround Playback Switch",
2938 "Center Playback Switch",
2939 "LFE Playback Switch",
2940 "Side Playback Switch",
2941 "Headphone Playback Switch",
2942 "Speaker Playback Switch",
2943 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01002944 "IEC958 Playback Switch",
Takashi Iwai23033b22009-12-08 12:36:52 +01002945 "Line-Out Playback Switch",
2946 "PCM Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002947 NULL,
2948};
2949
2950/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002951 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 */
Takashi Iwai603c4012008-07-30 15:01:44 +02002953
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002954#define NID_MAPPING (-1)
2955
2956#define SUBDEV_SPEAKER_ (0 << 6)
2957#define SUBDEV_HP_ (1 << 6)
2958#define SUBDEV_LINE_ (2 << 6)
2959#define SUBDEV_SPEAKER(x) (SUBDEV_SPEAKER_ | ((x) & 0x3f))
2960#define SUBDEV_HP(x) (SUBDEV_HP_ | ((x) & 0x3f))
2961#define SUBDEV_LINE(x) (SUBDEV_LINE_ | ((x) & 0x3f))
2962
Takashi Iwai603c4012008-07-30 15:01:44 +02002963static void alc_free_kctls(struct hda_codec *codec);
2964
Takashi Iwai67d634c2009-11-16 15:35:59 +01002965#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002966/* additional beep mixers; the actual parameters are overwritten at build */
2967static struct snd_kcontrol_new alc_beep_mixer[] = {
2968 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
Jaroslav Kysela123c07a2009-10-21 14:48:23 +02002969 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002970 { } /* end */
2971};
Takashi Iwai67d634c2009-11-16 15:35:59 +01002972#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002973
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974static int alc_build_controls(struct hda_codec *codec)
2975{
2976 struct alc_spec *spec = codec->spec;
Takashi Iwai2f44f842010-06-22 11:12:32 +02002977 struct snd_kcontrol *kctl = NULL;
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002978 struct snd_kcontrol_new *knew;
2979 int i, j, err;
2980 unsigned int u;
2981 hda_nid_t nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982
2983 for (i = 0; i < spec->num_mixers; i++) {
2984 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
2985 if (err < 0)
2986 return err;
2987 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002988 if (spec->cap_mixer) {
2989 err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
2990 if (err < 0)
2991 return err;
2992 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002994 err = snd_hda_create_spdif_out_ctls(codec,
2995 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996 if (err < 0)
2997 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002998 if (!spec->no_analog) {
2999 err = snd_hda_create_spdif_share_sw(codec,
3000 &spec->multiout);
3001 if (err < 0)
3002 return err;
3003 spec->multiout.share_spdif = 1;
3004 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005 }
3006 if (spec->dig_in_nid) {
3007 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
3008 if (err < 0)
3009 return err;
3010 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01003011
Takashi Iwai67d634c2009-11-16 15:35:59 +01003012#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003013 /* create beep controls if needed */
3014 if (spec->beep_amp) {
3015 struct snd_kcontrol_new *knew;
3016 for (knew = alc_beep_mixer; knew->name; knew++) {
3017 struct snd_kcontrol *kctl;
3018 kctl = snd_ctl_new1(knew, codec);
3019 if (!kctl)
3020 return -ENOMEM;
3021 kctl->private_value = spec->beep_amp;
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01003022 err = snd_hda_ctl_add(codec, 0, kctl);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003023 if (err < 0)
3024 return err;
3025 }
3026 }
Takashi Iwai67d634c2009-11-16 15:35:59 +01003027#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003028
Takashi Iwai2134ea42008-01-10 16:53:55 +01003029 /* if we have no master control, let's create it */
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003030 if (!spec->no_analog &&
3031 !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01003032 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01003033 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01003034 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01003035 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01003036 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01003037 if (err < 0)
3038 return err;
3039 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003040 if (!spec->no_analog &&
3041 !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003042 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
3043 NULL, alc_slave_sws);
3044 if (err < 0)
3045 return err;
3046 }
3047
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003048 /* assign Capture Source enums to NID */
Takashi Iwaifbe618f2010-06-11 11:24:58 +02003049 if (spec->capsrc_nids || spec->adc_nids) {
3050 kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
3051 if (!kctl)
3052 kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
3053 for (i = 0; kctl && i < kctl->count; i++) {
3054 hda_nid_t *nids = spec->capsrc_nids;
3055 if (!nids)
3056 nids = spec->adc_nids;
3057 err = snd_hda_add_nid(codec, kctl, i, nids[i]);
3058 if (err < 0)
3059 return err;
3060 }
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003061 }
3062 if (spec->cap_mixer) {
3063 const char *kname = kctl ? kctl->id.name : NULL;
3064 for (knew = spec->cap_mixer; knew->name; knew++) {
3065 if (kname && strcmp(knew->name, kname) == 0)
3066 continue;
3067 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
3068 for (i = 0; kctl && i < kctl->count; i++) {
3069 err = snd_hda_add_nid(codec, kctl, i,
3070 spec->adc_nids[i]);
3071 if (err < 0)
3072 return err;
3073 }
3074 }
3075 }
3076
3077 /* other nid->control mapping */
3078 for (i = 0; i < spec->num_mixers; i++) {
3079 for (knew = spec->mixers[i]; knew->name; knew++) {
3080 if (knew->iface != NID_MAPPING)
3081 continue;
3082 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
3083 if (kctl == NULL)
3084 continue;
3085 u = knew->subdevice;
3086 for (j = 0; j < 4; j++, u >>= 8) {
3087 nid = u & 0x3f;
3088 if (nid == 0)
3089 continue;
3090 switch (u & 0xc0) {
3091 case SUBDEV_SPEAKER_:
3092 nid = spec->autocfg.speaker_pins[nid];
3093 break;
3094 case SUBDEV_LINE_:
3095 nid = spec->autocfg.line_out_pins[nid];
3096 break;
3097 case SUBDEV_HP_:
3098 nid = spec->autocfg.hp_pins[nid];
3099 break;
3100 default:
3101 continue;
3102 }
3103 err = snd_hda_add_nid(codec, kctl, 0, nid);
3104 if (err < 0)
3105 return err;
3106 }
3107 u = knew->private_value;
3108 for (j = 0; j < 4; j++, u >>= 8) {
3109 nid = u & 0xff;
3110 if (nid == 0)
3111 continue;
3112 err = snd_hda_add_nid(codec, kctl, 0, nid);
3113 if (err < 0)
3114 return err;
3115 }
3116 }
3117 }
Takashi Iwaibae84e72010-03-22 08:30:20 +01003118
3119 alc_free_kctls(codec); /* no longer needed */
3120
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121 return 0;
3122}
3123
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003124
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125/*
3126 * initialize the codec volumes, etc
3127 */
3128
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003129/*
3130 * generic initialization of ADC, input mixers and output mixers
3131 */
3132static struct hda_verb alc880_volume_init_verbs[] = {
3133 /*
3134 * Unmute ADC0-2 and set the default input to mic-in
3135 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003136 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003137 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003138 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003139 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003140 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003141 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003143 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
3144 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003145 * Note: PASD motherboards uses the Line In 2 as the input for front
3146 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003148 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02003149 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3150 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3151 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3152 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3153 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
3154 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
3155 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003157 /*
3158 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003160 /* set vol=0 to output mixers */
3161 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3162 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3163 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3164 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3165 /* set up input amps for analog loopback */
3166 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003167 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3168 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02003169 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3170 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02003171 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3172 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02003173 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3174 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175
3176 { }
3177};
3178
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003179/*
3180 * 3-stack pin configuration:
3181 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
3182 */
3183static struct hda_verb alc880_pin_3stack_init_verbs[] = {
3184 /*
3185 * preset connection lists of input pins
3186 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
3187 */
3188 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
3189 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3190 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
3191
3192 /*
3193 * Set pin mode and muting
3194 */
3195 /* set front pin widgets 0x14 for output */
3196 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3197 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3198 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3199 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3200 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3201 /* Mic2 (as headphone out) for HP output */
3202 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3203 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3204 /* Line In pin widget for input */
3205 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3206 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3207 /* Line2 (as front mic) pin widget for input and vref at 80% */
3208 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3209 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3210 /* CD pin widget for input */
3211 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3212
3213 { }
3214};
3215
3216/*
3217 * 5-stack pin configuration:
3218 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
3219 * line-in/side = 0x1a, f-mic = 0x1b
3220 */
3221static struct hda_verb alc880_pin_5stack_init_verbs[] = {
3222 /*
3223 * preset connection lists of input pins
3224 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
3225 */
3226 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3227 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
3228
3229 /*
3230 * Set pin mode and muting
3231 */
3232 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02003233 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3234 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3235 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3236 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003237 /* unmute pins for output (no gain on this amp) */
3238 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3239 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3240 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3241 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3242
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02003244 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003245 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3246 /* Mic2 (as headphone out) for HP output */
3247 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02003248 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003249 /* Line In pin widget for input */
3250 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3251 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3252 /* Line2 (as front mic) pin widget for input and vref at 80% */
3253 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3254 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3255 /* CD pin widget for input */
3256 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257
3258 { }
3259};
3260
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003261/*
3262 * W810 pin configuration:
3263 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
3264 */
3265static struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 /* hphone/speaker input selector: front DAC */
3267 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
3268
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003269 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3270 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3271 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3272 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3273 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3274 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3275
3276 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02003277 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003278
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279 { }
3280};
3281
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003282/*
3283 * Z71V pin configuration:
3284 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
3285 */
3286static struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003287 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003288 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02003289 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003290 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02003291
Takashi Iwai16ded522005-06-10 19:58:24 +02003292 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003293 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02003294 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003295 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02003296
3297 { }
3298};
3299
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003300/*
3301 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003302 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
3303 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003304 */
3305static struct hda_verb alc880_pin_6stack_init_verbs[] = {
3306 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3307
Takashi Iwai16ded522005-06-10 19:58:24 +02003308 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003309 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003310 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003311 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003312 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003313 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003314 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003315 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3316
Takashi Iwai16ded522005-06-10 19:58:24 +02003317 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003318 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003319 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003320 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003321 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003322 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003323 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02003324 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003325 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02003326
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003327 { }
3328};
Takashi Iwai16ded522005-06-10 19:58:24 +02003329
Kailang Yangccc656c2006-10-17 12:32:26 +02003330/*
3331 * Uniwill pin configuration:
3332 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
3333 * line = 0x1a
3334 */
3335static struct hda_verb alc880_uniwill_init_verbs[] = {
3336 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3337
3338 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3339 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3340 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3341 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3342 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3343 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3344 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3345 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3346 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3347 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3348 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3349 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3350 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3351 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3352
3353 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3354 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3355 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3356 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3357 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3358 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3359 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
3360 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
3361 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3362
3363 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3364 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
3365
3366 { }
3367};
3368
3369/*
3370* Uniwill P53
Kailang Yangea1fb292008-08-26 12:58:38 +02003371* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
Kailang Yangccc656c2006-10-17 12:32:26 +02003372 */
3373static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
3374 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3375
3376 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3377 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3378 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3379 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3380 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3381 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3382 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3383 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3384 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3385 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3386 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3387 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3388
3389 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3390 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3391 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3392 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3393 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3394 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3395
3396 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3397 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
3398
3399 { }
3400};
3401
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003402static struct hda_verb alc880_beep_init_verbs[] = {
3403 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
3404 { }
3405};
3406
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003407/* auto-toggle front mic */
Anisse Astiereeb43382010-12-16 12:19:47 +01003408static void alc88x_simple_mic_automute(struct hda_codec *codec)
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003409{
3410 unsigned int present;
3411 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02003412
Wu Fengguang864f92b2009-11-18 12:38:02 +08003413 present = snd_hda_jack_detect(codec, 0x18);
Takashi Iwai47fd8302007-08-10 17:11:07 +02003414 bits = present ? HDA_AMP_MUTE : 0;
3415 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003416}
3417
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003418static void alc880_uniwill_setup(struct hda_codec *codec)
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003419{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003420 struct alc_spec *spec = codec->spec;
3421
3422 spec->autocfg.hp_pins[0] = 0x14;
3423 spec->autocfg.speaker_pins[0] = 0x15;
3424 spec->autocfg.speaker_pins[0] = 0x16;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003425}
3426
3427static void alc880_uniwill_init_hook(struct hda_codec *codec)
3428{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003429 alc_automute_amp(codec);
Anisse Astiereeb43382010-12-16 12:19:47 +01003430 alc88x_simple_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02003431}
3432
3433static void alc880_uniwill_unsol_event(struct hda_codec *codec,
3434 unsigned int res)
3435{
3436 /* Looks like the unsol event is incompatible with the standard
3437 * definition. 4bit tag is placed at 28 bit!
3438 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003439 switch (res >> 28) {
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003440 case ALC880_MIC_EVENT:
Anisse Astiereeb43382010-12-16 12:19:47 +01003441 alc88x_simple_mic_automute(codec);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003442 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003443 default:
3444 alc_automute_amp_unsol_event(codec, res);
3445 break;
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003446 }
Kailang Yangccc656c2006-10-17 12:32:26 +02003447}
3448
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003449static void alc880_uniwill_p53_setup(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02003450{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003451 struct alc_spec *spec = codec->spec;
Kailang Yangccc656c2006-10-17 12:32:26 +02003452
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003453 spec->autocfg.hp_pins[0] = 0x14;
3454 spec->autocfg.speaker_pins[0] = 0x15;
Kailang Yangccc656c2006-10-17 12:32:26 +02003455}
3456
3457static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
3458{
3459 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02003460
Kailang Yangccc656c2006-10-17 12:32:26 +02003461 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02003462 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
3463 present &= HDA_AMP_VOLMASK;
3464 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
3465 HDA_AMP_VOLMASK, present);
3466 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
3467 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02003468}
Takashi Iwai47fd8302007-08-10 17:11:07 +02003469
Kailang Yangccc656c2006-10-17 12:32:26 +02003470static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
3471 unsigned int res)
3472{
3473 /* Looks like the unsol event is incompatible with the standard
3474 * definition. 4bit tag is placed at 28 bit!
3475 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003476 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02003477 alc880_uniwill_p53_dcvol_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003478 else
3479 alc_automute_amp_unsol_event(codec, res);
Kailang Yangccc656c2006-10-17 12:32:26 +02003480}
3481
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003482/*
3483 * F1734 pin configuration:
3484 * HP = 0x14, speaker-out = 0x15, mic = 0x18
3485 */
3486static struct hda_verb alc880_pin_f1734_init_verbs[] = {
Michael Gruberee7a9c72008-03-10 11:30:59 +01003487 {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003488 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
3489 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
3490 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
3491 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
3492
3493 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3494 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3495 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3496 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3497
3498 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3499 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Michael Gruberee7a9c72008-03-10 11:30:59 +01003500 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003501 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3502 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3503 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3504 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3505 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3506 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02003507
Takashi Iwai937b4162008-02-11 14:52:36 +01003508 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
3509 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
3510
Takashi Iwai16ded522005-06-10 19:58:24 +02003511 { }
3512};
3513
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003514/*
3515 * ASUS pin configuration:
3516 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
3517 */
3518static struct hda_verb alc880_pin_asus_init_verbs[] = {
3519 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
3520 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
3521 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
3522 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
3523
3524 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3525 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3526 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3527 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3528 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3529 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3530 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3531 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3532
3533 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3534 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3535 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3536 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3537 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3538 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3539 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3540 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3541 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02003542
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003543 { }
3544};
3545
3546/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003547#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
3548#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
David Heidelberger64a8be72009-06-08 16:15:18 +02003549#define alc880_gpio3_init_verbs alc_gpio3_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003550
Kailang Yangdf694da2005-12-05 19:42:22 +01003551/* Clevo m520g init */
3552static struct hda_verb alc880_pin_clevo_init_verbs[] = {
3553 /* headphone output */
3554 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3555 /* line-out */
3556 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3557 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3558 /* Line-in */
3559 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3560 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3561 /* CD */
3562 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3563 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3564 /* Mic1 (rear panel) */
3565 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3566 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3567 /* Mic2 (front panel) */
3568 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3569 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3570 /* headphone */
3571 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3572 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3573 /* change to EAPD mode */
3574 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3575 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3576
3577 { }
3578};
3579
3580static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02003581 /* change to EAPD mode */
3582 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3583 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3584
Kailang Yangdf694da2005-12-05 19:42:22 +01003585 /* Headphone output */
3586 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3587 /* Front output*/
3588 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3589 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
3590
3591 /* Line In pin widget for input */
3592 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3593 /* CD pin widget for input */
3594 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3595 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3596 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3597
3598 /* change to EAPD mode */
3599 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3600 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
3601
3602 { }
3603};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003604
3605/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003606 * LG m1 express dual
3607 *
3608 * Pin assignment:
3609 * Rear Line-In/Out (blue): 0x14
3610 * Build-in Mic-In: 0x15
3611 * Speaker-out: 0x17
3612 * HP-Out (green): 0x1b
3613 * Mic-In/Out (red): 0x19
3614 * SPDIF-Out: 0x1e
3615 */
3616
3617/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
3618static hda_nid_t alc880_lg_dac_nids[3] = {
3619 0x05, 0x02, 0x03
3620};
3621
3622/* seems analog CD is not working */
3623static struct hda_input_mux alc880_lg_capture_source = {
3624 .num_items = 3,
3625 .items = {
3626 { "Mic", 0x1 },
3627 { "Line", 0x5 },
3628 { "Internal Mic", 0x6 },
3629 },
3630};
3631
3632/* 2,4,6 channel modes */
3633static struct hda_verb alc880_lg_ch2_init[] = {
3634 /* set line-in and mic-in to input */
3635 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
3636 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3637 { }
3638};
3639
3640static struct hda_verb alc880_lg_ch4_init[] = {
3641 /* set line-in to out and mic-in to input */
3642 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3643 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3644 { }
3645};
3646
3647static struct hda_verb alc880_lg_ch6_init[] = {
3648 /* set line-in and mic-in to output */
3649 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3650 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3651 { }
3652};
3653
3654static struct hda_channel_mode alc880_lg_ch_modes[3] = {
3655 { 2, alc880_lg_ch2_init },
3656 { 4, alc880_lg_ch4_init },
3657 { 6, alc880_lg_ch6_init },
3658};
3659
3660static struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003661 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
3662 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003663 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3664 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
3665 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
3666 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
3667 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
3668 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
3669 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3670 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
3671 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
3672 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
3673 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
3674 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
3675 {
3676 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3677 .name = "Channel Mode",
3678 .info = alc_ch_mode_info,
3679 .get = alc_ch_mode_get,
3680 .put = alc_ch_mode_put,
3681 },
3682 { } /* end */
3683};
3684
3685static struct hda_verb alc880_lg_init_verbs[] = {
3686 /* set capture source to mic-in */
3687 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3688 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3689 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3690 /* mute all amp mixer inputs */
3691 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02003692 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
3693 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003694 /* line-in to input */
3695 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3696 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3697 /* built-in mic */
3698 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3699 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3700 /* speaker-out */
3701 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3702 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3703 /* mic-in to input */
3704 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3705 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3706 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3707 /* HP-out */
3708 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
3709 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3710 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3711 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003712 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003713 { }
3714};
3715
3716/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003717static void alc880_lg_setup(struct hda_codec *codec)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003718{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003719 struct alc_spec *spec = codec->spec;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003720
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003721 spec->autocfg.hp_pins[0] = 0x1b;
3722 spec->autocfg.speaker_pins[0] = 0x17;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003723}
3724
3725/*
Takashi Iwaid6815182006-03-23 16:06:23 +01003726 * LG LW20
3727 *
3728 * Pin assignment:
3729 * Speaker-out: 0x14
3730 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003731 * Built-in Mic-In: 0x19
3732 * Line-In: 0x1b
3733 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01003734 * SPDIF-Out: 0x1e
3735 */
3736
Takashi Iwaid6815182006-03-23 16:06:23 +01003737static struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003738 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01003739 .items = {
3740 { "Mic", 0x0 },
3741 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003742 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003743 },
3744};
3745
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003746#define alc880_lg_lw_modes alc880_threestack_modes
3747
Takashi Iwaid6815182006-03-23 16:06:23 +01003748static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003749 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3750 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
3751 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
3752 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
3753 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
3754 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
3755 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
3756 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
3757 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
3758 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01003759 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3760 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3761 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
3762 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003763 {
3764 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3765 .name = "Channel Mode",
3766 .info = alc_ch_mode_info,
3767 .get = alc_ch_mode_get,
3768 .put = alc_ch_mode_put,
3769 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003770 { } /* end */
3771};
3772
3773static struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003774 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3775 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
3776 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
3777
Takashi Iwaid6815182006-03-23 16:06:23 +01003778 /* set capture source to mic-in */
3779 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3780 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3781 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02003782 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01003783 /* speaker-out */
3784 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3785 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3786 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01003787 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3788 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3789 /* mic-in to input */
3790 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3791 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3792 /* built-in mic */
3793 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3794 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3795 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003796 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaid6815182006-03-23 16:06:23 +01003797 { }
3798};
3799
3800/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003801static void alc880_lg_lw_setup(struct hda_codec *codec)
Takashi Iwaid6815182006-03-23 16:06:23 +01003802{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003803 struct alc_spec *spec = codec->spec;
Takashi Iwaid6815182006-03-23 16:06:23 +01003804
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003805 spec->autocfg.hp_pins[0] = 0x1b;
3806 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid6815182006-03-23 16:06:23 +01003807}
3808
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003809static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
3810 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3811 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
3812 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3813 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3814 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3815 HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
3816 { } /* end */
3817};
3818
3819static struct hda_input_mux alc880_medion_rim_capture_source = {
3820 .num_items = 2,
3821 .items = {
3822 { "Mic", 0x0 },
3823 { "Internal Mic", 0x1 },
3824 },
3825};
3826
3827static struct hda_verb alc880_medion_rim_init_verbs[] = {
3828 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3829
3830 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3831 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3832
3833 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3834 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3835 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3836 /* Mic2 (as headphone out) for HP output */
3837 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3838 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3839 /* Internal Speaker */
3840 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3841 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3842
3843 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3844 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3845
3846 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3847 { }
3848};
3849
3850/* toggle speaker-output according to the hp-jack state */
3851static void alc880_medion_rim_automute(struct hda_codec *codec)
3852{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003853 struct alc_spec *spec = codec->spec;
3854 alc_automute_amp(codec);
3855 /* toggle EAPD */
3856 if (spec->jack_present)
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003857 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
3858 else
3859 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
3860}
3861
3862static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
3863 unsigned int res)
3864{
3865 /* Looks like the unsol event is incompatible with the standard
3866 * definition. 4bit tag is placed at 28 bit!
3867 */
3868 if ((res >> 28) == ALC880_HP_EVENT)
3869 alc880_medion_rim_automute(codec);
3870}
3871
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003872static void alc880_medion_rim_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003873{
3874 struct alc_spec *spec = codec->spec;
3875
3876 spec->autocfg.hp_pins[0] = 0x14;
3877 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003878}
3879
Takashi Iwaicb53c622007-08-10 17:21:45 +02003880#ifdef CONFIG_SND_HDA_POWER_SAVE
3881static struct hda_amp_list alc880_loopbacks[] = {
3882 { 0x0b, HDA_INPUT, 0 },
3883 { 0x0b, HDA_INPUT, 1 },
3884 { 0x0b, HDA_INPUT, 2 },
3885 { 0x0b, HDA_INPUT, 3 },
3886 { 0x0b, HDA_INPUT, 4 },
3887 { } /* end */
3888};
3889
3890static struct hda_amp_list alc880_lg_loopbacks[] = {
3891 { 0x0b, HDA_INPUT, 1 },
3892 { 0x0b, HDA_INPUT, 6 },
3893 { 0x0b, HDA_INPUT, 7 },
3894 { } /* end */
3895};
3896#endif
3897
Takashi Iwaid6815182006-03-23 16:06:23 +01003898/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003899 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003900 */
Takashi Iwai16ded522005-06-10 19:58:24 +02003901
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902static int alc_init(struct hda_codec *codec)
3903{
3904 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003905 unsigned int i;
3906
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02003907 alc_fix_pll(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02003908 alc_auto_init_amp(codec, spec->init_amp);
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02003909
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003910 for (i = 0; i < spec->num_init_verbs; i++)
3911 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003912
3913 if (spec->init_hook)
3914 spec->init_hook(codec);
3915
Takashi Iwai58701122011-01-13 15:41:45 +01003916 alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT);
3917
Takashi Iwai9e5341b2010-09-21 09:57:06 +02003918 hda_call_check_power_status(codec, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003919 return 0;
3920}
3921
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003922static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
3923{
3924 struct alc_spec *spec = codec->spec;
3925
3926 if (spec->unsol_event)
3927 spec->unsol_event(codec, res);
3928}
3929
Takashi Iwaicb53c622007-08-10 17:21:45 +02003930#ifdef CONFIG_SND_HDA_POWER_SAVE
3931static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
3932{
3933 struct alc_spec *spec = codec->spec;
3934 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
3935}
3936#endif
3937
Linus Torvalds1da177e2005-04-16 15:20:36 -07003938/*
3939 * Analog playback callbacks
3940 */
3941static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
3942 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003943 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944{
3945 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01003946 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
3947 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003948}
3949
3950static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
3951 struct hda_codec *codec,
3952 unsigned int stream_tag,
3953 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003954 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003955{
3956 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003957 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
3958 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959}
3960
3961static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3962 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003963 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964{
3965 struct alc_spec *spec = codec->spec;
3966 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
3967}
3968
3969/*
3970 * Digital out
3971 */
3972static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
3973 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003974 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975{
3976 struct alc_spec *spec = codec->spec;
3977 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
3978}
3979
Takashi Iwai6b97eb42007-04-05 14:51:48 +02003980static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
3981 struct hda_codec *codec,
3982 unsigned int stream_tag,
3983 unsigned int format,
3984 struct snd_pcm_substream *substream)
3985{
3986 struct alc_spec *spec = codec->spec;
3987 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
3988 stream_tag, format, substream);
3989}
3990
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01003991static int alc880_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3992 struct hda_codec *codec,
3993 struct snd_pcm_substream *substream)
3994{
3995 struct alc_spec *spec = codec->spec;
3996 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
3997}
3998
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
4000 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004001 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004002{
4003 struct alc_spec *spec = codec->spec;
4004 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
4005}
4006
4007/*
4008 * Analog capture
4009 */
Takashi Iwai63300792008-01-24 15:31:36 +01004010static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011 struct hda_codec *codec,
4012 unsigned int stream_tag,
4013 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004014 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015{
4016 struct alc_spec *spec = codec->spec;
4017
Takashi Iwai63300792008-01-24 15:31:36 +01004018 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019 stream_tag, 0, format);
4020 return 0;
4021}
4022
Takashi Iwai63300792008-01-24 15:31:36 +01004023static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004025 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026{
4027 struct alc_spec *spec = codec->spec;
4028
Takashi Iwai888afa12008-03-18 09:57:50 +01004029 snd_hda_codec_cleanup_stream(codec,
4030 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004031 return 0;
4032}
4033
Takashi Iwai840b64c2010-07-13 22:49:01 +02004034/* analog capture with dynamic dual-adc changes */
4035static int dualmic_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
4036 struct hda_codec *codec,
4037 unsigned int stream_tag,
4038 unsigned int format,
4039 struct snd_pcm_substream *substream)
4040{
4041 struct alc_spec *spec = codec->spec;
4042 spec->cur_adc = spec->adc_nids[spec->cur_adc_idx];
4043 spec->cur_adc_stream_tag = stream_tag;
4044 spec->cur_adc_format = format;
4045 snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
4046 return 0;
4047}
4048
4049static int dualmic_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
4050 struct hda_codec *codec,
4051 struct snd_pcm_substream *substream)
4052{
4053 struct alc_spec *spec = codec->spec;
4054 snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
4055 spec->cur_adc = 0;
4056 return 0;
4057}
4058
4059static struct hda_pcm_stream dualmic_pcm_analog_capture = {
4060 .substreams = 1,
4061 .channels_min = 2,
4062 .channels_max = 2,
4063 .nid = 0, /* fill later */
4064 .ops = {
4065 .prepare = dualmic_capture_pcm_prepare,
4066 .cleanup = dualmic_capture_pcm_cleanup
4067 },
4068};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069
4070/*
4071 */
4072static struct hda_pcm_stream alc880_pcm_analog_playback = {
4073 .substreams = 1,
4074 .channels_min = 2,
4075 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004076 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004077 .ops = {
4078 .open = alc880_playback_pcm_open,
4079 .prepare = alc880_playback_pcm_prepare,
4080 .cleanup = alc880_playback_pcm_cleanup
4081 },
4082};
4083
4084static struct hda_pcm_stream alc880_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01004085 .substreams = 1,
4086 .channels_min = 2,
4087 .channels_max = 2,
4088 /* NID is set in alc_build_pcms */
4089};
4090
4091static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
4092 .substreams = 1,
4093 .channels_min = 2,
4094 .channels_max = 2,
4095 /* NID is set in alc_build_pcms */
4096};
4097
4098static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
4099 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100 .channels_min = 2,
4101 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004102 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004103 .ops = {
Takashi Iwai63300792008-01-24 15:31:36 +01004104 .prepare = alc880_alt_capture_pcm_prepare,
4105 .cleanup = alc880_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106 },
4107};
4108
4109static struct hda_pcm_stream alc880_pcm_digital_playback = {
4110 .substreams = 1,
4111 .channels_min = 2,
4112 .channels_max = 2,
4113 /* NID is set in alc_build_pcms */
4114 .ops = {
4115 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02004116 .close = alc880_dig_playback_pcm_close,
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01004117 .prepare = alc880_dig_playback_pcm_prepare,
4118 .cleanup = alc880_dig_playback_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07004119 },
4120};
4121
4122static struct hda_pcm_stream alc880_pcm_digital_capture = {
4123 .substreams = 1,
4124 .channels_min = 2,
4125 .channels_max = 2,
4126 /* NID is set in alc_build_pcms */
4127};
4128
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004129/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwai63300792008-01-24 15:31:36 +01004130static struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004131 .substreams = 0,
4132 .channels_min = 0,
4133 .channels_max = 0,
4134};
4135
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136static int alc_build_pcms(struct hda_codec *codec)
4137{
4138 struct alc_spec *spec = codec->spec;
4139 struct hda_pcm *info = spec->pcm_rec;
4140 int i;
4141
4142 codec->num_pcms = 1;
4143 codec->pcm_info = info;
4144
Takashi Iwaie64f14f2009-01-20 18:32:55 +01004145 if (spec->no_analog)
4146 goto skip_analog;
4147
Takashi Iwai812a2cc2009-05-16 10:00:49 +02004148 snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog),
4149 "%s Analog", codec->chip_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150 info->name = spec->stream_name_analog;
Kailang Yang274693f2009-12-03 10:07:50 +01004151
Takashi Iwai4a471b72005-12-07 13:56:29 +01004152 if (spec->stream_analog_playback) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02004153 if (snd_BUG_ON(!spec->multiout.dac_nids))
4154 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004155 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
4156 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
4157 }
4158 if (spec->stream_analog_capture) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02004159 if (snd_BUG_ON(!spec->adc_nids))
4160 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004161 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
4162 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
4163 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164
Takashi Iwai4a471b72005-12-07 13:56:29 +01004165 if (spec->channel_mode) {
4166 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
4167 for (i = 0; i < spec->num_channel_mode; i++) {
4168 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
4169 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
4170 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171 }
4172 }
4173
Takashi Iwaie64f14f2009-01-20 18:32:55 +01004174 skip_analog:
Takashi Iwaie08a0072006-09-07 17:52:14 +02004175 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwai812a2cc2009-05-16 10:00:49 +02004177 snprintf(spec->stream_name_digital,
4178 sizeof(spec->stream_name_digital),
4179 "%s Digital", codec->chip_name);
Takashi Iwaie08a0072006-09-07 17:52:14 +02004180 codec->num_pcms = 2;
Wu Fengguangb25c9da2009-02-06 15:02:27 +08004181 codec->slave_dig_outs = spec->multiout.slave_dig_outs;
Takashi Iwaic06134d2006-10-11 18:49:13 +02004182 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183 info->name = spec->stream_name_digital;
Takashi Iwai8c441982009-01-20 18:30:20 +01004184 if (spec->dig_out_type)
4185 info->pcm_type = spec->dig_out_type;
4186 else
4187 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004188 if (spec->multiout.dig_out_nid &&
4189 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
4191 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
4192 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01004193 if (spec->dig_in_nid &&
4194 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
4196 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
4197 }
Takashi Iwai963f8032008-08-11 10:04:40 +02004198 /* FIXME: do we need this for all Realtek codec models? */
4199 codec->spdif_status_reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004200 }
4201
Takashi Iwaie64f14f2009-01-20 18:32:55 +01004202 if (spec->no_analog)
4203 return 0;
4204
Takashi Iwaie08a0072006-09-07 17:52:14 +02004205 /* If the use of more than one ADC is requested for the current
4206 * model, configure a second analog capture-only PCM.
4207 */
4208 /* Additional Analaog capture for index #2 */
Takashi Iwai63300792008-01-24 15:31:36 +01004209 if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
4210 (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02004211 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02004212 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02004213 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01004214 if (spec->alt_dac_nid) {
4215 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
4216 *spec->stream_analog_alt_playback;
4217 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
4218 spec->alt_dac_nid;
4219 } else {
4220 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
4221 alc_pcm_null_stream;
4222 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
4223 }
4224 if (spec->num_adc_nids > 1) {
4225 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
4226 *spec->stream_analog_alt_capture;
4227 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
4228 spec->adc_nids[1];
4229 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
4230 spec->num_adc_nids - 1;
4231 } else {
4232 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
4233 alc_pcm_null_stream;
4234 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02004235 }
4236 }
4237
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238 return 0;
4239}
4240
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004241static inline void alc_shutup(struct hda_codec *codec)
4242{
4243 snd_hda_shutup_pins(codec);
4244}
4245
Takashi Iwai603c4012008-07-30 15:01:44 +02004246static void alc_free_kctls(struct hda_codec *codec)
4247{
4248 struct alc_spec *spec = codec->spec;
4249
4250 if (spec->kctls.list) {
4251 struct snd_kcontrol_new *kctl = spec->kctls.list;
4252 int i;
4253 for (i = 0; i < spec->kctls.used; i++)
4254 kfree(kctl[i].name);
4255 }
4256 snd_array_free(&spec->kctls);
4257}
4258
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259static void alc_free(struct hda_codec *codec)
4260{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004261 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004262
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004263 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004264 return;
4265
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004266 alc_shutup(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +02004267 alc_free_kctls(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004268 kfree(spec);
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09004269 snd_hda_detach_beep_device(codec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270}
4271
Hector Martinf5de24b2009-12-20 22:51:31 +01004272#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -05004273static void alc_power_eapd(struct hda_codec *codec)
4274{
4275 /* We currently only handle front, HP */
4276 switch (codec->vendor_id) {
4277 case 0x10ec0260:
Takashi Iwai9e4c8492010-01-19 15:53:43 +01004278 set_eapd(codec, 0x0f, 0);
4279 set_eapd(codec, 0x10, 0);
Daniel T Chenc97259d2009-12-27 18:52:08 -05004280 break;
4281 case 0x10ec0262:
4282 case 0x10ec0267:
4283 case 0x10ec0268:
4284 case 0x10ec0269:
Takashi Iwai9e4c8492010-01-19 15:53:43 +01004285 case 0x10ec0270:
Daniel T Chenc97259d2009-12-27 18:52:08 -05004286 case 0x10ec0272:
4287 case 0x10ec0660:
4288 case 0x10ec0662:
4289 case 0x10ec0663:
4290 case 0x10ec0862:
4291 case 0x10ec0889:
Takashi Iwai9e4c8492010-01-19 15:53:43 +01004292 set_eapd(codec, 0x14, 0);
4293 set_eapd(codec, 0x15, 0);
Daniel T Chenc97259d2009-12-27 18:52:08 -05004294 break;
4295 }
4296}
4297
Hector Martinf5de24b2009-12-20 22:51:31 +01004298static int alc_suspend(struct hda_codec *codec, pm_message_t state)
4299{
4300 struct alc_spec *spec = codec->spec;
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004301 alc_shutup(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01004302 if (spec && spec->power_hook)
Daniel T Chenc97259d2009-12-27 18:52:08 -05004303 spec->power_hook(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01004304 return 0;
4305}
4306#endif
4307
Takashi Iwaie044c392008-10-27 16:56:24 +01004308#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaie044c392008-10-27 16:56:24 +01004309static int alc_resume(struct hda_codec *codec)
4310{
Takashi Iwaie044c392008-10-27 16:56:24 +01004311 codec->patch_ops.init(codec);
4312 snd_hda_codec_resume_amp(codec);
4313 snd_hda_codec_resume_cache(codec);
Takashi Iwai9e5341b2010-09-21 09:57:06 +02004314 hda_call_check_power_status(codec, 0x01);
Takashi Iwaie044c392008-10-27 16:56:24 +01004315 return 0;
4316}
Takashi Iwaie044c392008-10-27 16:56:24 +01004317#endif
4318
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319/*
4320 */
4321static struct hda_codec_ops alc_patch_ops = {
4322 .build_controls = alc_build_controls,
4323 .build_pcms = alc_build_pcms,
4324 .init = alc_init,
4325 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004326 .unsol_event = alc_unsol_event,
Takashi Iwaie044c392008-10-27 16:56:24 +01004327#ifdef SND_HDA_NEEDS_RESUME
4328 .resume = alc_resume,
4329#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02004330#ifdef CONFIG_SND_HDA_POWER_SAVE
Hector Martinf5de24b2009-12-20 22:51:31 +01004331 .suspend = alc_suspend,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004332 .check_power_status = alc_check_power_status,
4333#endif
Daniel T Chenc97259d2009-12-27 18:52:08 -05004334 .reboot_notify = alc_shutup,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335};
4336
Kailang Yangc027ddc2010-03-19 11:33:06 +01004337/* replace the codec chip_name with the given string */
4338static int alc_codec_rename(struct hda_codec *codec, const char *name)
4339{
4340 kfree(codec->chip_name);
4341 codec->chip_name = kstrdup(name, GFP_KERNEL);
4342 if (!codec->chip_name) {
4343 alc_free(codec);
4344 return -ENOMEM;
4345 }
4346 return 0;
4347}
4348
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004349/*
4350 * Test configuration for debugging
4351 *
4352 * Almost all inputs/outputs are enabled. I/O pins can be configured via
4353 * enum controls.
4354 */
4355#ifdef CONFIG_SND_DEBUG
4356static hda_nid_t alc880_test_dac_nids[4] = {
4357 0x02, 0x03, 0x04, 0x05
4358};
4359
4360static struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004361 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004362 .items = {
4363 { "In-1", 0x0 },
4364 { "In-2", 0x1 },
4365 { "In-3", 0x2 },
4366 { "In-4", 0x3 },
4367 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004368 { "Front", 0x5 },
4369 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004370 },
4371};
4372
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01004373static struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004374 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02004375 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004376 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02004377 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004378};
4379
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004380static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
4381 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004382{
4383 static char *texts[] = {
4384 "N/A", "Line Out", "HP Out",
4385 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
4386 };
4387 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
4388 uinfo->count = 1;
4389 uinfo->value.enumerated.items = 8;
4390 if (uinfo->value.enumerated.item >= 8)
4391 uinfo->value.enumerated.item = 7;
4392 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
4393 return 0;
4394}
4395
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004396static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
4397 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004398{
4399 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4400 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4401 unsigned int pin_ctl, item = 0;
4402
4403 pin_ctl = snd_hda_codec_read(codec, nid, 0,
4404 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
4405 if (pin_ctl & AC_PINCTL_OUT_EN) {
4406 if (pin_ctl & AC_PINCTL_HP_EN)
4407 item = 2;
4408 else
4409 item = 1;
4410 } else if (pin_ctl & AC_PINCTL_IN_EN) {
4411 switch (pin_ctl & AC_PINCTL_VREFEN) {
4412 case AC_PINCTL_VREF_HIZ: item = 3; break;
4413 case AC_PINCTL_VREF_50: item = 4; break;
4414 case AC_PINCTL_VREF_GRD: item = 5; break;
4415 case AC_PINCTL_VREF_80: item = 6; break;
4416 case AC_PINCTL_VREF_100: item = 7; break;
4417 }
4418 }
4419 ucontrol->value.enumerated.item[0] = item;
4420 return 0;
4421}
4422
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004423static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
4424 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004425{
4426 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4427 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4428 static unsigned int ctls[] = {
4429 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
4430 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
4431 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
4432 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
4433 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
4434 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
4435 };
4436 unsigned int old_ctl, new_ctl;
4437
4438 old_ctl = snd_hda_codec_read(codec, nid, 0,
4439 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
4440 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
4441 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004442 int val;
4443 snd_hda_codec_write_cache(codec, nid, 0,
4444 AC_VERB_SET_PIN_WIDGET_CONTROL,
4445 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02004446 val = ucontrol->value.enumerated.item[0] >= 3 ?
4447 HDA_AMP_MUTE : 0;
4448 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
4449 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004450 return 1;
4451 }
4452 return 0;
4453}
4454
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004455static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
4456 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004457{
4458 static char *texts[] = {
4459 "Front", "Surround", "CLFE", "Side"
4460 };
4461 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
4462 uinfo->count = 1;
4463 uinfo->value.enumerated.items = 4;
4464 if (uinfo->value.enumerated.item >= 4)
4465 uinfo->value.enumerated.item = 3;
4466 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
4467 return 0;
4468}
4469
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004470static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
4471 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004472{
4473 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4474 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4475 unsigned int sel;
4476
4477 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
4478 ucontrol->value.enumerated.item[0] = sel & 3;
4479 return 0;
4480}
4481
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004482static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
4483 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004484{
4485 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4486 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4487 unsigned int sel;
4488
4489 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
4490 if (ucontrol->value.enumerated.item[0] != sel) {
4491 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004492 snd_hda_codec_write_cache(codec, nid, 0,
4493 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004494 return 1;
4495 }
4496 return 0;
4497}
4498
4499#define PIN_CTL_TEST(xname,nid) { \
4500 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
4501 .name = xname, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01004502 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004503 .info = alc_test_pin_ctl_info, \
4504 .get = alc_test_pin_ctl_get, \
4505 .put = alc_test_pin_ctl_put, \
4506 .private_value = nid \
4507 }
4508
4509#define PIN_SRC_TEST(xname,nid) { \
4510 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
4511 .name = xname, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01004512 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004513 .info = alc_test_pin_src_info, \
4514 .get = alc_test_pin_src_get, \
4515 .put = alc_test_pin_src_put, \
4516 .private_value = nid \
4517 }
4518
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004519static struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02004520 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
4521 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
4522 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
4523 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004524 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
4525 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
4526 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
4527 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004528 PIN_CTL_TEST("Front Pin Mode", 0x14),
4529 PIN_CTL_TEST("Surround Pin Mode", 0x15),
4530 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
4531 PIN_CTL_TEST("Side Pin Mode", 0x17),
4532 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
4533 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
4534 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
4535 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
4536 PIN_SRC_TEST("In-1 Pin Source", 0x18),
4537 PIN_SRC_TEST("In-2 Pin Source", 0x19),
4538 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
4539 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
4540 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
4541 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
4542 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
4543 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
4544 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
4545 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
4546 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
4547 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
4548 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
4549 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004550 {
4551 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4552 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01004553 .info = alc_ch_mode_info,
4554 .get = alc_ch_mode_get,
4555 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004556 },
4557 { } /* end */
4558};
4559
4560static struct hda_verb alc880_test_init_verbs[] = {
4561 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02004562 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4563 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4564 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4565 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4566 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4567 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4568 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4569 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004570 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02004571 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4572 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4573 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4574 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004575 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004576 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4577 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4578 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4579 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004580 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004581 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4582 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4583 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4584 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004585 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02004586 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4587 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02004588 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4589 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4590 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004591 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02004592 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4593 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4594 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4595 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004596 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02004597 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004598 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004599 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004600 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004601 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004602 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004603 /* Analog input/passthru */
4604 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4605 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4606 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4607 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4608 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004609 { }
4610};
4611#endif
4612
Linus Torvalds1da177e2005-04-16 15:20:36 -07004613/*
4614 */
4615
Takashi Iwaiea734962011-01-17 11:29:34 +01004616static const char * const alc880_models[ALC880_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004617 [ALC880_3ST] = "3stack",
4618 [ALC880_TCL_S700] = "tcl",
4619 [ALC880_3ST_DIG] = "3stack-digout",
4620 [ALC880_CLEVO] = "clevo",
4621 [ALC880_5ST] = "5stack",
4622 [ALC880_5ST_DIG] = "5stack-digout",
4623 [ALC880_W810] = "w810",
4624 [ALC880_Z71V] = "z71v",
4625 [ALC880_6ST] = "6stack",
4626 [ALC880_6ST_DIG] = "6stack-digout",
4627 [ALC880_ASUS] = "asus",
4628 [ALC880_ASUS_W1V] = "asus-w1v",
4629 [ALC880_ASUS_DIG] = "asus-dig",
4630 [ALC880_ASUS_DIG2] = "asus-dig2",
4631 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004632 [ALC880_UNIWILL_P53] = "uniwill-p53",
4633 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004634 [ALC880_F1734] = "F1734",
4635 [ALC880_LG] = "lg",
4636 [ALC880_LG_LW] = "lg-lw",
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004637 [ALC880_MEDION_RIM] = "medion",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004638#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004639 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004640#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004641 [ALC880_AUTO] = "auto",
4642};
4643
4644static struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004645 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004646 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
4647 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
4648 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
4649 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
4650 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
4651 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
4652 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
4653 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004654 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
4655 SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004656 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
4657 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
4658 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
4659 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
4660 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
4661 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
4662 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
4663 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
4664 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
4665 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Travis Place186c3112008-05-20 11:54:41 +02004666 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004667 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
4668 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
4669 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004670 SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004671 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004672 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
4673 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004674 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
4675 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004676 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
4677 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
4678 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
4679 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004680 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
4681 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004682 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004683 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004684 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004685 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004686 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
4687 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004688 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004689 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004690 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004691 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004692 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Travis Place1d116042008-06-23 11:42:30 +02004693 SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
Daniel T Chen33535412010-04-22 07:15:26 -04004694 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_F1734),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004695 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004696 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004697 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
Daniel T Chen77c4d5c2010-12-02 22:45:45 -05004698 SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004699 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004700 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004701 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
4702 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
4703 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
4704 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004705 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
4706 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004707 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004708 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004709 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
4710 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004711 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
4712 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
4713 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004714 /* default Intel */
4715 SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004716 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
4717 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004718 {}
4719};
4720
Takashi Iwai16ded522005-06-10 19:58:24 +02004721/*
Kailang Yangdf694da2005-12-05 19:42:22 +01004722 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02004723 */
Takashi Iwai16ded522005-06-10 19:58:24 +02004724static struct alc_config_preset alc880_presets[] = {
4725 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004726 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004727 .init_verbs = { alc880_volume_init_verbs,
4728 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004729 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02004730 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004731 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4732 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004733 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004734 .input_mux = &alc880_capture_source,
4735 },
4736 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004737 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004738 .init_verbs = { alc880_volume_init_verbs,
4739 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004740 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02004741 .dac_nids = alc880_dac_nids,
4742 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004743 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4744 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004745 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004746 .input_mux = &alc880_capture_source,
4747 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004748 [ALC880_TCL_S700] = {
4749 .mixers = { alc880_tcl_s700_mixer },
4750 .init_verbs = { alc880_volume_init_verbs,
4751 alc880_pin_tcl_S700_init_verbs,
4752 alc880_gpio2_init_verbs },
4753 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4754 .dac_nids = alc880_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004755 .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */
4756 .num_adc_nids = 1, /* single ADC */
Kailang Yangdf694da2005-12-05 19:42:22 +01004757 .hp_nid = 0x03,
4758 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4759 .channel_mode = alc880_2_jack_modes,
4760 .input_mux = &alc880_capture_source,
4761 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004762 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004763 .mixers = { alc880_three_stack_mixer,
4764 alc880_five_stack_mixer},
4765 .init_verbs = { alc880_volume_init_verbs,
4766 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004767 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4768 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004769 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
4770 .channel_mode = alc880_fivestack_modes,
4771 .input_mux = &alc880_capture_source,
4772 },
4773 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004774 .mixers = { alc880_three_stack_mixer,
4775 alc880_five_stack_mixer },
4776 .init_verbs = { alc880_volume_init_verbs,
4777 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004778 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4779 .dac_nids = alc880_dac_nids,
4780 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004781 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
4782 .channel_mode = alc880_fivestack_modes,
4783 .input_mux = &alc880_capture_source,
4784 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02004785 [ALC880_6ST] = {
4786 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004787 .init_verbs = { alc880_volume_init_verbs,
4788 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02004789 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
4790 .dac_nids = alc880_6st_dac_nids,
4791 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
4792 .channel_mode = alc880_sixstack_modes,
4793 .input_mux = &alc880_6stack_capture_source,
4794 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004795 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004796 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004797 .init_verbs = { alc880_volume_init_verbs,
4798 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004799 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
4800 .dac_nids = alc880_6st_dac_nids,
4801 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004802 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
4803 .channel_mode = alc880_sixstack_modes,
4804 .input_mux = &alc880_6stack_capture_source,
4805 },
4806 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004807 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004808 .init_verbs = { alc880_volume_init_verbs,
4809 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02004810 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004811 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
4812 .dac_nids = alc880_w810_dac_nids,
4813 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004814 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
4815 .channel_mode = alc880_w810_modes,
4816 .input_mux = &alc880_capture_source,
4817 },
4818 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004819 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004820 .init_verbs = { alc880_volume_init_verbs,
4821 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004822 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
4823 .dac_nids = alc880_z71v_dac_nids,
4824 .dig_out_nid = ALC880_DIGOUT_NID,
4825 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004826 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4827 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02004828 .input_mux = &alc880_capture_source,
4829 },
4830 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004831 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004832 .init_verbs = { alc880_volume_init_verbs,
4833 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004834 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
4835 .dac_nids = alc880_f1734_dac_nids,
4836 .hp_nid = 0x02,
4837 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4838 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01004839 .input_mux = &alc880_f1734_capture_source,
4840 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004841 .setup = alc880_uniwill_p53_setup,
4842 .init_hook = alc_automute_amp,
Takashi Iwai16ded522005-06-10 19:58:24 +02004843 },
4844 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004845 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004846 .init_verbs = { alc880_volume_init_verbs,
4847 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004848 alc880_gpio1_init_verbs },
4849 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4850 .dac_nids = alc880_asus_dac_nids,
4851 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4852 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004853 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004854 .input_mux = &alc880_capture_source,
4855 },
4856 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004857 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004858 .init_verbs = { alc880_volume_init_verbs,
4859 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004860 alc880_gpio1_init_verbs },
4861 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4862 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004863 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004864 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4865 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004866 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004867 .input_mux = &alc880_capture_source,
4868 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004869 [ALC880_ASUS_DIG2] = {
4870 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004871 .init_verbs = { alc880_volume_init_verbs,
4872 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01004873 alc880_gpio2_init_verbs }, /* use GPIO2 */
4874 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4875 .dac_nids = alc880_asus_dac_nids,
4876 .dig_out_nid = ALC880_DIGOUT_NID,
4877 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4878 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004879 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01004880 .input_mux = &alc880_capture_source,
4881 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004882 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004883 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004884 .init_verbs = { alc880_volume_init_verbs,
4885 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004886 alc880_gpio1_init_verbs },
4887 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4888 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004889 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004890 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4891 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004892 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004893 .input_mux = &alc880_capture_source,
4894 },
4895 [ALC880_UNIWILL_DIG] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004896 .mixers = { alc880_asus_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02004897 .init_verbs = { alc880_volume_init_verbs,
4898 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004899 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4900 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004901 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004902 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4903 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004904 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004905 .input_mux = &alc880_capture_source,
4906 },
Kailang Yangccc656c2006-10-17 12:32:26 +02004907 [ALC880_UNIWILL] = {
4908 .mixers = { alc880_uniwill_mixer },
4909 .init_verbs = { alc880_volume_init_verbs,
4910 alc880_uniwill_init_verbs },
4911 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4912 .dac_nids = alc880_asus_dac_nids,
4913 .dig_out_nid = ALC880_DIGOUT_NID,
4914 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4915 .channel_mode = alc880_threestack_modes,
4916 .need_dac_fix = 1,
4917 .input_mux = &alc880_capture_source,
4918 .unsol_event = alc880_uniwill_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004919 .setup = alc880_uniwill_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004920 .init_hook = alc880_uniwill_init_hook,
Kailang Yangccc656c2006-10-17 12:32:26 +02004921 },
4922 [ALC880_UNIWILL_P53] = {
4923 .mixers = { alc880_uniwill_p53_mixer },
4924 .init_verbs = { alc880_volume_init_verbs,
4925 alc880_uniwill_p53_init_verbs },
4926 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4927 .dac_nids = alc880_asus_dac_nids,
4928 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004929 .channel_mode = alc880_threestack_modes,
4930 .input_mux = &alc880_capture_source,
4931 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004932 .setup = alc880_uniwill_p53_setup,
4933 .init_hook = alc_automute_amp,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004934 },
4935 [ALC880_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004936 .mixers = { alc880_fujitsu_mixer },
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004937 .init_verbs = { alc880_volume_init_verbs,
4938 alc880_uniwill_p53_init_verbs,
4939 alc880_beep_init_verbs },
4940 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4941 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02004942 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004943 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4944 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02004945 .input_mux = &alc880_capture_source,
4946 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004947 .setup = alc880_uniwill_p53_setup,
4948 .init_hook = alc_automute_amp,
Kailang Yangccc656c2006-10-17 12:32:26 +02004949 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004950 [ALC880_CLEVO] = {
4951 .mixers = { alc880_three_stack_mixer },
4952 .init_verbs = { alc880_volume_init_verbs,
4953 alc880_pin_clevo_init_verbs },
4954 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4955 .dac_nids = alc880_dac_nids,
4956 .hp_nid = 0x03,
4957 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4958 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004959 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01004960 .input_mux = &alc880_capture_source,
4961 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004962 [ALC880_LG] = {
4963 .mixers = { alc880_lg_mixer },
4964 .init_verbs = { alc880_volume_init_verbs,
4965 alc880_lg_init_verbs },
4966 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
4967 .dac_nids = alc880_lg_dac_nids,
4968 .dig_out_nid = ALC880_DIGOUT_NID,
4969 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
4970 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004971 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004972 .input_mux = &alc880_lg_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004973 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004974 .setup = alc880_lg_setup,
4975 .init_hook = alc_automute_amp,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004976#ifdef CONFIG_SND_HDA_POWER_SAVE
4977 .loopbacks = alc880_lg_loopbacks,
4978#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004979 },
Takashi Iwaid6815182006-03-23 16:06:23 +01004980 [ALC880_LG_LW] = {
4981 .mixers = { alc880_lg_lw_mixer },
4982 .init_verbs = { alc880_volume_init_verbs,
4983 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004984 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01004985 .dac_nids = alc880_dac_nids,
4986 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004987 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
4988 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01004989 .input_mux = &alc880_lg_lw_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004990 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004991 .setup = alc880_lg_lw_setup,
4992 .init_hook = alc_automute_amp,
Takashi Iwaid6815182006-03-23 16:06:23 +01004993 },
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004994 [ALC880_MEDION_RIM] = {
4995 .mixers = { alc880_medion_rim_mixer },
4996 .init_verbs = { alc880_volume_init_verbs,
4997 alc880_medion_rim_init_verbs,
4998 alc_gpio2_init_verbs },
4999 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5000 .dac_nids = alc880_dac_nids,
5001 .dig_out_nid = ALC880_DIGOUT_NID,
5002 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
5003 .channel_mode = alc880_2_jack_modes,
5004 .input_mux = &alc880_medion_rim_capture_source,
5005 .unsol_event = alc880_medion_rim_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005006 .setup = alc880_medion_rim_setup,
5007 .init_hook = alc880_medion_rim_automute,
Takashi Iwaidf99cd32008-04-25 15:25:04 +02005008 },
Takashi Iwai16ded522005-06-10 19:58:24 +02005009#ifdef CONFIG_SND_DEBUG
5010 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005011 .mixers = { alc880_test_mixer },
5012 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005013 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
5014 .dac_nids = alc880_test_dac_nids,
5015 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02005016 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
5017 .channel_mode = alc880_test_modes,
5018 .input_mux = &alc880_test_capture_source,
5019 },
5020#endif
5021};
5022
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005023/*
5024 * Automatic parse of I/O pins from the BIOS configuration
5025 */
5026
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005027enum {
5028 ALC_CTL_WIDGET_VOL,
5029 ALC_CTL_WIDGET_MUTE,
5030 ALC_CTL_BIND_MUTE,
5031};
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01005032static struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005033 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
5034 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01005035 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005036};
5037
5038/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005039static int add_control(struct alc_spec *spec, int type, const char *name,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005040 int cidx, unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005041{
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01005042 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005043
Takashi Iwai603c4012008-07-30 15:01:44 +02005044 snd_array_init(&spec->kctls, sizeof(*knew), 32);
5045 knew = snd_array_new(&spec->kctls);
5046 if (!knew)
5047 return -ENOMEM;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005048 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07005049 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005050 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005051 return -ENOMEM;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005052 knew->index = cidx;
Jaroslav Kysela4d02d1b2009-11-12 10:15:48 +01005053 if (get_amp_nid_(val))
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01005054 knew->subdevice = HDA_SUBDEV_AMP_FLAG;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005055 knew->private_value = val;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005056 return 0;
5057}
5058
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005059static int add_control_with_pfx(struct alc_spec *spec, int type,
5060 const char *pfx, const char *dir,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005061 const char *sfx, int cidx, unsigned long val)
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005062{
5063 char name[32];
5064 snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005065 return add_control(spec, type, name, cidx, val);
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005066}
5067
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005068#define add_pb_vol_ctrl(spec, type, pfx, val) \
5069 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
5070#define add_pb_sw_ctrl(spec, type, pfx, val) \
5071 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
5072#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \
5073 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
5074#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \
5075 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005076
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005077#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
5078#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
5079#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
5080#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005081#define alc880_idx_to_dac(nid) ((nid) + 0x02)
5082#define alc880_dac_to_idx(nid) ((nid) - 0x02)
5083#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
5084#define alc880_idx_to_selector(nid) ((nid) + 0x10)
5085#define ALC880_PIN_CD_NID 0x1c
5086
5087/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005088static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
5089 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005090{
5091 hda_nid_t nid;
5092 int assigned[4];
5093 int i, j;
5094
5095 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02005096 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005097
5098 /* check the pins hardwired to audio widget */
5099 for (i = 0; i < cfg->line_outs; i++) {
5100 nid = cfg->line_out_pins[i];
5101 if (alc880_is_fixed_pin(nid)) {
5102 int idx = alc880_fixed_pin_idx(nid);
Libin Yang5014f192005-11-23 15:48:36 +01005103 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005104 assigned[idx] = 1;
5105 }
5106 }
5107 /* left pins can be connect to any audio widget */
5108 for (i = 0; i < cfg->line_outs; i++) {
5109 nid = cfg->line_out_pins[i];
5110 if (alc880_is_fixed_pin(nid))
5111 continue;
5112 /* search for an empty channel */
5113 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005114 if (!assigned[j]) {
5115 spec->multiout.dac_nids[i] =
5116 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005117 assigned[j] = 1;
5118 break;
5119 }
5120 }
5121 }
5122 spec->multiout.num_dacs = cfg->line_outs;
5123 return 0;
5124}
5125
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005126static const char *alc_get_line_out_pfx(const struct auto_pin_cfg *cfg,
5127 bool can_be_master)
5128{
5129 if (!cfg->hp_outs && !cfg->speaker_outs && can_be_master)
5130 return "Master";
5131
5132 switch (cfg->line_out_type) {
5133 case AUTO_PIN_SPEAKER_OUT:
5134 return "Speaker";
5135 case AUTO_PIN_HP_OUT:
5136 return "Headphone";
5137 default:
5138 if (cfg->line_outs == 1)
5139 return "PCM";
5140 break;
5141 }
5142 return NULL;
5143}
5144
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005145/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01005146static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
5147 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005148{
Takashi Iwaiea734962011-01-17 11:29:34 +01005149 static const char * const chname[4] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005150 "Front", "Surround", NULL /*CLFE*/, "Side"
5151 };
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005152 const char *pfx = alc_get_line_out_pfx(cfg, false);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005153 hda_nid_t nid;
5154 int i, err;
5155
5156 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005157 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005158 continue;
5159 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005160 if (!pfx && i == 2) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005161 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005162 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
5163 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005164 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
5165 HDA_OUTPUT));
5166 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005167 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005168 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
5169 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005170 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
5171 HDA_OUTPUT));
5172 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005173 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005174 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
5175 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005176 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
5177 HDA_INPUT));
5178 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005179 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005180 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
5181 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005182 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
5183 HDA_INPUT));
5184 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005185 return err;
5186 } else {
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005187 const char *name = pfx;
5188 if (!name)
5189 name = chname[i];
5190 err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
5191 name, i,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005192 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
5193 HDA_OUTPUT));
5194 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005195 return err;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005196 err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
5197 name, i,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005198 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
5199 HDA_INPUT));
5200 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005201 return err;
5202 }
5203 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005204 return 0;
5205}
5206
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005207/* add playback controls for speaker and HP outputs */
5208static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
5209 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005210{
5211 hda_nid_t nid;
5212 int err;
5213
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005214 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005215 return 0;
5216
5217 if (alc880_is_fixed_pin(pin)) {
5218 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01005219 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005220 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005221 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01005222 else
5223 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005224 /* control HP volume/switch on the output mixer amp */
5225 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005226 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005227 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
5228 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005229 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005230 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005231 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
5232 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005233 return err;
5234 } else if (alc880_is_multi_pin(pin)) {
5235 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005236 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005237 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005238 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
5239 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005240 return err;
5241 }
5242 return 0;
5243}
5244
5245/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005246static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005247 const char *ctlname, int ctlidx,
Kailang Yangdf694da2005-12-05 19:42:22 +01005248 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005249{
Kailang Yangdf694da2005-12-05 19:42:22 +01005250 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005251
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005252 err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, ctlidx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005253 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
5254 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005255 return err;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005256 err = __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, ctlidx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005257 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
5258 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005259 return err;
5260 return 0;
5261}
5262
Takashi Iwai05f5f472009-08-25 13:10:18 +02005263static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005264{
Takashi Iwai05f5f472009-08-25 13:10:18 +02005265 unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
5266 return (pincap & AC_PINCAP_IN) != 0;
5267}
5268
5269/* create playback/capture controls for input pins */
5270static int alc_auto_create_input_ctls(struct hda_codec *codec,
5271 const struct auto_pin_cfg *cfg,
5272 hda_nid_t mixer,
5273 hda_nid_t cap1, hda_nid_t cap2)
5274{
5275 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005276 struct hda_input_mux *imux = &spec->private_imux[0];
David Henningsson5322bf22011-01-05 11:03:56 +01005277 int i, err, idx, type_idx = 0;
5278 const char *prev_label = NULL;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005279
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005280 for (i = 0; i < cfg->num_inputs; i++) {
Takashi Iwai05f5f472009-08-25 13:10:18 +02005281 hda_nid_t pin;
Takashi Iwai10a20af2010-09-09 16:28:02 +02005282 const char *label;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005283
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005284 pin = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005285 if (!alc_is_input_pin(codec, pin))
5286 continue;
5287
David Henningsson5322bf22011-01-05 11:03:56 +01005288 label = hda_get_autocfg_input_label(codec, cfg, i);
5289 if (prev_label && !strcmp(label, prev_label))
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005290 type_idx++;
5291 else
5292 type_idx = 0;
David Henningsson5322bf22011-01-05 11:03:56 +01005293 prev_label = label;
5294
Takashi Iwai05f5f472009-08-25 13:10:18 +02005295 if (mixer) {
5296 idx = get_connection_index(codec, mixer, pin);
5297 if (idx >= 0) {
5298 err = new_analog_input(spec, pin,
Takashi Iwai10a20af2010-09-09 16:28:02 +02005299 label, type_idx,
5300 idx, mixer);
Takashi Iwai05f5f472009-08-25 13:10:18 +02005301 if (err < 0)
5302 return err;
5303 }
5304 }
5305
5306 if (!cap1)
5307 continue;
5308 idx = get_connection_index(codec, cap1, pin);
5309 if (idx < 0 && cap2)
5310 idx = get_connection_index(codec, cap2, pin);
Takashi Iwai10a20af2010-09-09 16:28:02 +02005311 if (idx >= 0)
5312 snd_hda_add_imux_item(imux, label, idx, NULL);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005313 }
5314 return 0;
5315}
5316
Takashi Iwai05f5f472009-08-25 13:10:18 +02005317static int alc880_auto_create_input_ctls(struct hda_codec *codec,
5318 const struct auto_pin_cfg *cfg)
5319{
5320 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x08, 0x09);
5321}
5322
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005323static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
5324 unsigned int pin_type)
5325{
5326 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5327 pin_type);
5328 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01005329 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
5330 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005331}
5332
Kailang Yangdf694da2005-12-05 19:42:22 +01005333static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
5334 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005335 int dac_idx)
5336{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005337 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005338 /* need the manual connection? */
5339 if (alc880_is_multi_pin(nid)) {
5340 struct alc_spec *spec = codec->spec;
5341 int idx = alc880_multi_pin_idx(nid);
5342 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
5343 AC_VERB_SET_CONNECT_SEL,
5344 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
5345 }
5346}
5347
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005348static int get_pin_type(int line_out_type)
5349{
5350 if (line_out_type == AUTO_PIN_HP_OUT)
5351 return PIN_HP;
5352 else
5353 return PIN_OUT;
5354}
5355
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005356static void alc880_auto_init_multi_out(struct hda_codec *codec)
5357{
5358 struct alc_spec *spec = codec->spec;
5359 int i;
Kailang Yangea1fb292008-08-26 12:58:38 +02005360
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005361 for (i = 0; i < spec->autocfg.line_outs; i++) {
5362 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005363 int pin_type = get_pin_type(spec->autocfg.line_out_type);
5364 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005365 }
5366}
5367
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005368static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005369{
5370 struct alc_spec *spec = codec->spec;
5371 hda_nid_t pin;
5372
Takashi Iwai82bc9552006-03-21 11:24:42 +01005373 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005374 if (pin) /* connect to front */
5375 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005376 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005377 if (pin) /* connect to front */
5378 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
5379}
5380
5381static void alc880_auto_init_analog_input(struct hda_codec *codec)
5382{
5383 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005384 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005385 int i;
5386
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005387 for (i = 0; i < cfg->num_inputs; i++) {
5388 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005389 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai30ea0982010-09-16 18:47:56 +02005390 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwaie82c0252009-03-23 15:17:38 +01005391 if (nid != ALC880_PIN_CD_NID &&
5392 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005393 snd_hda_codec_write(codec, nid, 0,
5394 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005395 AMP_OUT_MUTE);
5396 }
5397 }
5398}
5399
Takashi Iwai7f311a42010-04-09 17:32:23 +02005400static void alc880_auto_init_input_src(struct hda_codec *codec)
5401{
5402 struct alc_spec *spec = codec->spec;
5403 int c;
5404
5405 for (c = 0; c < spec->num_adc_nids; c++) {
5406 unsigned int mux_idx;
5407 const struct hda_input_mux *imux;
5408 mux_idx = c >= spec->num_mux_defs ? 0 : c;
5409 imux = &spec->input_mux[mux_idx];
5410 if (!imux->num_items && mux_idx > 0)
5411 imux = &spec->input_mux[0];
5412 if (imux)
5413 snd_hda_codec_write(codec, spec->adc_nids[c], 0,
5414 AC_VERB_SET_CONNECT_SEL,
5415 imux->items[0].index);
5416 }
5417}
5418
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005419/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005420/* return 1 if successful, 0 if the proper config is not found,
5421 * or a negative error code
5422 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005423static int alc880_parse_auto_config(struct hda_codec *codec)
5424{
5425 struct alc_spec *spec = codec->spec;
Takashi Iwai757899a2010-07-30 10:48:14 +02005426 int err;
Kailang Yangdf694da2005-12-05 19:42:22 +01005427 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005428
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005429 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
5430 alc880_ignore);
5431 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005432 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005433 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005434 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01005435
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005436 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
5437 if (err < 0)
5438 return err;
5439 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
5440 if (err < 0)
5441 return err;
5442 err = alc880_auto_create_extra_out(spec,
5443 spec->autocfg.speaker_pins[0],
5444 "Speaker");
5445 if (err < 0)
5446 return err;
5447 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
5448 "Headphone");
5449 if (err < 0)
5450 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005451 err = alc880_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005452 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005453 return err;
5454
5455 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
5456
Takashi Iwai757899a2010-07-30 10:48:14 +02005457 alc_auto_parse_digital(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005458
Takashi Iwai603c4012008-07-30 15:01:44 +02005459 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01005460 add_mixer(spec, spec->kctls.list);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005461
Takashi Iwaid88897e2008-10-31 15:01:37 +01005462 add_verb(spec, alc880_volume_init_verbs);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005463
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005464 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005465 spec->input_mux = &spec->private_imux[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005466
Kailang Yang6227cdc2010-02-25 08:36:52 +01005467 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02005468
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005469 return 1;
5470}
5471
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005472/* additional initialization for auto-configuration model */
5473static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005474{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005475 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005476 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005477 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005478 alc880_auto_init_analog_input(codec);
Takashi Iwai7f311a42010-04-09 17:32:23 +02005479 alc880_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +02005480 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005481 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02005482 alc_inithook(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005483}
5484
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005485/* check the ADC/MUX contains all input pins; some ADC/MUX contains only
5486 * one of two digital mic pins, e.g. on ALC272
5487 */
5488static void fixup_automic_adc(struct hda_codec *codec)
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005489{
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005490 struct alc_spec *spec = codec->spec;
5491 int i;
5492
5493 for (i = 0; i < spec->num_adc_nids; i++) {
5494 hda_nid_t cap = spec->capsrc_nids ?
5495 spec->capsrc_nids[i] : spec->adc_nids[i];
5496 int iidx, eidx;
5497
5498 iidx = get_connection_index(codec, cap, spec->int_mic.pin);
5499 if (iidx < 0)
5500 continue;
5501 eidx = get_connection_index(codec, cap, spec->ext_mic.pin);
5502 if (eidx < 0)
5503 continue;
5504 spec->int_mic.mux_idx = iidx;
5505 spec->ext_mic.mux_idx = eidx;
5506 if (spec->capsrc_nids)
5507 spec->capsrc_nids += i;
5508 spec->adc_nids += i;
5509 spec->num_adc_nids = 1;
5510 return;
5511 }
5512 snd_printd(KERN_INFO "hda_codec: %s: "
5513 "No ADC/MUX containing both 0x%x and 0x%x pins\n",
5514 codec->chip_name, spec->int_mic.pin, spec->ext_mic.pin);
5515 spec->auto_mic = 0; /* disable auto-mic to be sure */
5516}
5517
Takashi Iwai748cce42010-08-04 07:37:39 +02005518/* select or unmute the given capsrc route */
5519static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap,
5520 int idx)
5521{
5522 if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
5523 snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
5524 HDA_AMP_MUTE, 0);
5525 } else {
5526 snd_hda_codec_write_cache(codec, cap, 0,
5527 AC_VERB_SET_CONNECT_SEL, idx);
5528 }
5529}
5530
Takashi Iwai840b64c2010-07-13 22:49:01 +02005531/* set the default connection to that pin */
5532static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
5533{
5534 struct alc_spec *spec = codec->spec;
5535 int i;
5536
5537 for (i = 0; i < spec->num_adc_nids; i++) {
5538 hda_nid_t cap = spec->capsrc_nids ?
5539 spec->capsrc_nids[i] : spec->adc_nids[i];
5540 int idx;
5541
5542 idx = get_connection_index(codec, cap, pin);
5543 if (idx < 0)
5544 continue;
Takashi Iwai748cce42010-08-04 07:37:39 +02005545 select_or_unmute_capsrc(codec, cap, idx);
Takashi Iwai840b64c2010-07-13 22:49:01 +02005546 return i; /* return the found index */
5547 }
5548 return -1; /* not found */
5549}
5550
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005551/* choose the ADC/MUX containing the input pin and initialize the setup */
5552static void fixup_single_adc(struct hda_codec *codec)
5553{
5554 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005555 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005556 int i;
5557
5558 /* search for the input pin; there must be only one */
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005559 if (cfg->num_inputs != 1)
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005560 return;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005561 i = init_capsrc_for_pin(codec, cfg->inputs[0].pin);
Takashi Iwai840b64c2010-07-13 22:49:01 +02005562 if (i >= 0) {
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005563 /* use only this ADC */
5564 if (spec->capsrc_nids)
5565 spec->capsrc_nids += i;
5566 spec->adc_nids += i;
5567 spec->num_adc_nids = 1;
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005568 }
5569}
5570
Takashi Iwai840b64c2010-07-13 22:49:01 +02005571/* initialize dual adcs */
5572static void fixup_dual_adc_switch(struct hda_codec *codec)
5573{
5574 struct alc_spec *spec = codec->spec;
5575 init_capsrc_for_pin(codec, spec->ext_mic.pin);
5576 init_capsrc_for_pin(codec, spec->int_mic.pin);
5577}
5578
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005579static void set_capture_mixer(struct hda_codec *codec)
5580{
5581 struct alc_spec *spec = codec->spec;
Takashi Iwaia23b6882009-03-23 15:21:36 +01005582 static struct snd_kcontrol_new *caps[2][3] = {
5583 { alc_capture_mixer_nosrc1,
5584 alc_capture_mixer_nosrc2,
5585 alc_capture_mixer_nosrc3 },
5586 { alc_capture_mixer1,
5587 alc_capture_mixer2,
5588 alc_capture_mixer3 },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005589 };
Takashi Iwaia23b6882009-03-23 15:21:36 +01005590 if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005591 int mux = 0;
Takashi Iwai840b64c2010-07-13 22:49:01 +02005592 int num_adcs = spec->num_adc_nids;
5593 if (spec->dual_adc_switch)
5594 fixup_dual_adc_switch(codec);
5595 else if (spec->auto_mic)
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005596 fixup_automic_adc(codec);
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005597 else if (spec->input_mux) {
5598 if (spec->input_mux->num_items > 1)
5599 mux = 1;
5600 else if (spec->input_mux->num_items == 1)
5601 fixup_single_adc(codec);
5602 }
Takashi Iwai840b64c2010-07-13 22:49:01 +02005603 if (spec->dual_adc_switch)
5604 num_adcs = 1;
5605 spec->cap_mixer = caps[mux][num_adcs - 1];
Takashi Iwaia23b6882009-03-23 15:21:36 +01005606 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005607}
5608
Takashi Iwai66946352010-03-29 17:21:45 +02005609/* fill adc_nids (and capsrc_nids) containing all active input pins */
5610static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids,
5611 int num_nids)
5612{
5613 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005614 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai66946352010-03-29 17:21:45 +02005615 int n;
5616 hda_nid_t fallback_adc = 0, fallback_cap = 0;
5617
5618 for (n = 0; n < num_nids; n++) {
5619 hda_nid_t adc, cap;
5620 hda_nid_t conn[HDA_MAX_NUM_INPUTS];
5621 int nconns, i, j;
5622
5623 adc = nids[n];
5624 if (get_wcaps_type(get_wcaps(codec, adc)) != AC_WID_AUD_IN)
5625 continue;
5626 cap = adc;
5627 nconns = snd_hda_get_connections(codec, cap, conn,
5628 ARRAY_SIZE(conn));
5629 if (nconns == 1) {
5630 cap = conn[0];
5631 nconns = snd_hda_get_connections(codec, cap, conn,
5632 ARRAY_SIZE(conn));
5633 }
5634 if (nconns <= 0)
5635 continue;
5636 if (!fallback_adc) {
5637 fallback_adc = adc;
5638 fallback_cap = cap;
5639 }
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005640 for (i = 0; i < cfg->num_inputs; i++) {
5641 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai66946352010-03-29 17:21:45 +02005642 for (j = 0; j < nconns; j++) {
5643 if (conn[j] == nid)
5644 break;
5645 }
5646 if (j >= nconns)
5647 break;
5648 }
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005649 if (i >= cfg->num_inputs) {
Takashi Iwai66946352010-03-29 17:21:45 +02005650 int num_adcs = spec->num_adc_nids;
5651 spec->private_adc_nids[num_adcs] = adc;
5652 spec->private_capsrc_nids[num_adcs] = cap;
5653 spec->num_adc_nids++;
5654 spec->adc_nids = spec->private_adc_nids;
5655 if (adc != cap)
5656 spec->capsrc_nids = spec->private_capsrc_nids;
5657 }
5658 }
5659 if (!spec->num_adc_nids) {
5660 printk(KERN_WARNING "hda_codec: %s: no valid ADC found;"
Takashi Iwai1f85d722010-03-30 07:48:05 +02005661 " using fallback 0x%x\n",
5662 codec->chip_name, fallback_adc);
Takashi Iwai66946352010-03-29 17:21:45 +02005663 spec->private_adc_nids[0] = fallback_adc;
5664 spec->adc_nids = spec->private_adc_nids;
5665 if (fallback_adc != fallback_cap) {
5666 spec->private_capsrc_nids[0] = fallback_cap;
5667 spec->capsrc_nids = spec->private_adc_nids;
5668 }
5669 }
5670}
5671
Takashi Iwai67d634c2009-11-16 15:35:59 +01005672#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005673#define set_beep_amp(spec, nid, idx, dir) \
5674 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005675
5676static struct snd_pci_quirk beep_white_list[] = {
5677 SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
Takashi Iwai080dc7b2010-09-08 08:38:41 +02005678 SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
Takashi Iwaie096c8e2010-08-03 17:20:35 +02005679 SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005680 {}
5681};
5682
5683static inline int has_cdefine_beep(struct hda_codec *codec)
5684{
5685 struct alc_spec *spec = codec->spec;
5686 const struct snd_pci_quirk *q;
5687 q = snd_pci_quirk_lookup(codec->bus->pci, beep_white_list);
5688 if (q)
5689 return q->value;
5690 return spec->cdefine.enable_pcbeep;
5691}
Takashi Iwai67d634c2009-11-16 15:35:59 +01005692#else
5693#define set_beep_amp(spec, nid, idx, dir) /* NOP */
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005694#define has_cdefine_beep(codec) 0
Takashi Iwai67d634c2009-11-16 15:35:59 +01005695#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005696
5697/*
5698 * OK, here we have finally the patch for ALC880
5699 */
5700
Linus Torvalds1da177e2005-04-16 15:20:36 -07005701static int patch_alc880(struct hda_codec *codec)
5702{
5703 struct alc_spec *spec;
5704 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01005705 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005706
Takashi Iwaie560d8d2005-09-09 14:21:46 +02005707 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005708 if (spec == NULL)
5709 return -ENOMEM;
5710
5711 codec->spec = spec;
5712
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005713 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
5714 alc880_models,
5715 alc880_cfg_tbl);
5716 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02005717 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
5718 codec->chip_name);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005719 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005720 }
5721
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005722 if (board_config == ALC880_AUTO) {
5723 /* automatic parse from the BIOS config */
5724 err = alc880_parse_auto_config(codec);
5725 if (err < 0) {
5726 alc_free(codec);
5727 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005728 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005729 printk(KERN_INFO
5730 "hda_codec: Cannot set up configuration "
5731 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005732 board_config = ALC880_3ST;
5733 }
5734 }
5735
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09005736 err = snd_hda_attach_beep_device(codec, 0x1);
5737 if (err < 0) {
5738 alc_free(codec);
5739 return err;
5740 }
5741
Kailang Yangdf694da2005-12-05 19:42:22 +01005742 if (board_config != ALC880_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02005743 setup_preset(codec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005744
Linus Torvalds1da177e2005-04-16 15:20:36 -07005745 spec->stream_analog_playback = &alc880_pcm_analog_playback;
5746 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01005747 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005748
Linus Torvalds1da177e2005-04-16 15:20:36 -07005749 spec->stream_digital_playback = &alc880_pcm_digital_playback;
5750 spec->stream_digital_capture = &alc880_pcm_digital_capture;
5751
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005752 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005753 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01005754 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005755 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +02005756 wcap = get_wcaps_type(wcap);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005757 if (wcap != AC_WID_AUD_IN) {
5758 spec->adc_nids = alc880_adc_nids_alt;
5759 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005760 } else {
5761 spec->adc_nids = alc880_adc_nids;
5762 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005763 }
5764 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005765 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005766 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005767
Takashi Iwai2134ea42008-01-10 16:53:55 +01005768 spec->vmaster_nid = 0x0c;
5769
Linus Torvalds1da177e2005-04-16 15:20:36 -07005770 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005771 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005772 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02005773#ifdef CONFIG_SND_HDA_POWER_SAVE
5774 if (!spec->loopback.amplist)
5775 spec->loopback.amplist = alc880_loopbacks;
5776#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005777
5778 return 0;
5779}
5780
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005781
Linus Torvalds1da177e2005-04-16 15:20:36 -07005782/*
5783 * ALC260 support
5784 */
5785
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005786static hda_nid_t alc260_dac_nids[1] = {
5787 /* front */
5788 0x02,
5789};
5790
5791static hda_nid_t alc260_adc_nids[1] = {
5792 /* ADC0 */
5793 0x04,
5794};
5795
Kailang Yangdf694da2005-12-05 19:42:22 +01005796static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005797 /* ADC1 */
5798 0x05,
5799};
5800
Jonathan Woithed57fdac2006-02-28 11:38:35 +01005801/* NIDs used when simultaneous access to both ADCs makes sense. Note that
5802 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
5803 */
5804static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005805 /* ADC0, ADC1 */
5806 0x04, 0x05
5807};
5808
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005809#define ALC260_DIGOUT_NID 0x03
5810#define ALC260_DIGIN_NID 0x06
5811
5812static struct hda_input_mux alc260_capture_source = {
5813 .num_items = 4,
5814 .items = {
5815 { "Mic", 0x0 },
5816 { "Front Mic", 0x1 },
5817 { "Line", 0x2 },
5818 { "CD", 0x4 },
5819 },
5820};
5821
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01005822/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005823 * headphone jack and the internal CD lines since these are the only pins at
5824 * which audio can appear. For flexibility, also allow the option of
5825 * recording the mixer output on the second ADC (ADC0 doesn't have a
5826 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005827 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005828static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
5829 {
5830 .num_items = 3,
5831 .items = {
5832 { "Mic/Line", 0x0 },
5833 { "CD", 0x4 },
5834 { "Headphone", 0x2 },
5835 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005836 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005837 {
5838 .num_items = 4,
5839 .items = {
5840 { "Mic/Line", 0x0 },
5841 { "CD", 0x4 },
5842 { "Headphone", 0x2 },
5843 { "Mixer", 0x5 },
5844 },
5845 },
5846
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005847};
5848
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005849/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
5850 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005851 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005852static struct hda_input_mux alc260_acer_capture_sources[2] = {
5853 {
5854 .num_items = 4,
5855 .items = {
5856 { "Mic", 0x0 },
5857 { "Line", 0x2 },
5858 { "CD", 0x4 },
5859 { "Headphone", 0x5 },
5860 },
5861 },
5862 {
5863 .num_items = 5,
5864 .items = {
5865 { "Mic", 0x0 },
5866 { "Line", 0x2 },
5867 { "CD", 0x4 },
5868 { "Headphone", 0x6 },
5869 { "Mixer", 0x5 },
5870 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005871 },
5872};
Michael Schwingencc959482009-02-22 18:58:45 +01005873
5874/* Maxdata Favorit 100XS */
5875static struct hda_input_mux alc260_favorit100_capture_sources[2] = {
5876 {
5877 .num_items = 2,
5878 .items = {
5879 { "Line/Mic", 0x0 },
5880 { "CD", 0x4 },
5881 },
5882 },
5883 {
5884 .num_items = 3,
5885 .items = {
5886 { "Line/Mic", 0x0 },
5887 { "CD", 0x4 },
5888 { "Mixer", 0x5 },
5889 },
5890 },
5891};
5892
Linus Torvalds1da177e2005-04-16 15:20:36 -07005893/*
5894 * This is just place-holder, so there's something for alc_build_pcms to look
5895 * at when it calculates the maximum number of channels. ALC260 has no mixer
5896 * element which allows changing the channel mode, so the verb list is
5897 * never used.
5898 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01005899static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005900 { 2, NULL },
5901};
5902
Kailang Yangdf694da2005-12-05 19:42:22 +01005903
5904/* Mixer combinations
5905 *
5906 * basic: base_output + input + pc_beep + capture
5907 * HP: base_output + input + capture_alt
5908 * HP_3013: hp_3013 + input + capture
5909 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005910 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01005911 */
5912
5913static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02005914 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005915 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01005916 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5917 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
5918 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5919 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5920 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005921};
Kailang Yangdf694da2005-12-05 19:42:22 +01005922
5923static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005924 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5925 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5926 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5927 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5928 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5929 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5930 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
5931 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005932 { } /* end */
5933};
5934
Takashi Iwaibec15c32008-01-28 18:16:30 +01005935/* update HP, line and mono out pins according to the master switch */
5936static void alc260_hp_master_update(struct hda_codec *codec,
5937 hda_nid_t hp, hda_nid_t line,
5938 hda_nid_t mono)
5939{
5940 struct alc_spec *spec = codec->spec;
5941 unsigned int val = spec->master_sw ? PIN_HP : 0;
5942 /* change HP and line-out pins */
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005943 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005944 val);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005945 snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005946 val);
5947 /* mono (speaker) depending on the HP jack sense */
5948 val = (val && !spec->jack_present) ? PIN_OUT : 0;
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005949 snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005950 val);
5951}
5952
5953static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
5954 struct snd_ctl_elem_value *ucontrol)
5955{
5956 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5957 struct alc_spec *spec = codec->spec;
5958 *ucontrol->value.integer.value = spec->master_sw;
5959 return 0;
5960}
5961
5962static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
5963 struct snd_ctl_elem_value *ucontrol)
5964{
5965 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5966 struct alc_spec *spec = codec->spec;
5967 int val = !!*ucontrol->value.integer.value;
5968 hda_nid_t hp, line, mono;
5969
5970 if (val == spec->master_sw)
5971 return 0;
5972 spec->master_sw = val;
5973 hp = (kcontrol->private_value >> 16) & 0xff;
5974 line = (kcontrol->private_value >> 8) & 0xff;
5975 mono = kcontrol->private_value & 0xff;
5976 alc260_hp_master_update(codec, hp, line, mono);
5977 return 1;
5978}
5979
5980static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
5981 {
5982 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5983 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01005984 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005985 .info = snd_ctl_boolean_mono_info,
5986 .get = alc260_hp_master_sw_get,
5987 .put = alc260_hp_master_sw_put,
5988 .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
5989 },
5990 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5991 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
5992 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5993 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
5994 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
5995 HDA_OUTPUT),
5996 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5997 { } /* end */
5998};
5999
6000static struct hda_verb alc260_hp_unsol_verbs[] = {
6001 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6002 {},
6003};
6004
6005static void alc260_hp_automute(struct hda_codec *codec)
6006{
6007 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006008
Wu Fengguang864f92b2009-11-18 12:38:02 +08006009 spec->jack_present = snd_hda_jack_detect(codec, 0x10);
Takashi Iwaibec15c32008-01-28 18:16:30 +01006010 alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
6011}
6012
6013static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
6014{
6015 if ((res >> 26) == ALC880_HP_EVENT)
6016 alc260_hp_automute(codec);
6017}
6018
Kailang Yangdf694da2005-12-05 19:42:22 +01006019static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006020 {
6021 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6022 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01006023 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006024 .info = snd_ctl_boolean_mono_info,
6025 .get = alc260_hp_master_sw_get,
6026 .put = alc260_hp_master_sw_put,
Takashi Iwai30cde0a2008-11-07 14:49:28 +01006027 .private_value = (0x15 << 16) | (0x10 << 8) | 0x11
Takashi Iwaibec15c32008-01-28 18:16:30 +01006028 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006029 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6030 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
6031 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
6032 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
6033 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6034 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01006035 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
6036 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02006037 { } /* end */
6038};
6039
Kailang Yang3f878302008-08-26 13:02:23 +02006040static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
6041 .ops = &snd_hda_bind_vol,
6042 .values = {
6043 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
6044 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
6045 HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
6046 0
6047 },
6048};
6049
6050static struct hda_bind_ctls alc260_dc7600_bind_switch = {
6051 .ops = &snd_hda_bind_sw,
6052 .values = {
6053 HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
6054 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
6055 0
6056 },
6057};
6058
6059static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
6060 HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
6061 HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
6062 HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
6063 HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
6064 { } /* end */
6065};
6066
Takashi Iwaibec15c32008-01-28 18:16:30 +01006067static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
6068 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6069 {},
6070};
6071
6072static void alc260_hp_3013_automute(struct hda_codec *codec)
6073{
6074 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006075
Wu Fengguang864f92b2009-11-18 12:38:02 +08006076 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01006077 alc260_hp_master_update(codec, 0x15, 0x10, 0x11);
Takashi Iwaibec15c32008-01-28 18:16:30 +01006078}
6079
6080static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
6081 unsigned int res)
6082{
6083 if ((res >> 26) == ALC880_HP_EVENT)
6084 alc260_hp_3013_automute(codec);
6085}
6086
Kailang Yang3f878302008-08-26 13:02:23 +02006087static void alc260_hp_3012_automute(struct hda_codec *codec)
6088{
Wu Fengguang864f92b2009-11-18 12:38:02 +08006089 unsigned int bits = snd_hda_jack_detect(codec, 0x10) ? 0 : PIN_OUT;
Kailang Yang3f878302008-08-26 13:02:23 +02006090
Kailang Yang3f878302008-08-26 13:02:23 +02006091 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
6092 bits);
6093 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
6094 bits);
6095 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
6096 bits);
6097}
6098
6099static void alc260_hp_3012_unsol_event(struct hda_codec *codec,
6100 unsigned int res)
6101{
6102 if ((res >> 26) == ALC880_HP_EVENT)
6103 alc260_hp_3012_automute(codec);
6104}
6105
6106/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006107 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
6108 */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01006109static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006110 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006111 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006112 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006113 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6114 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
6115 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
6116 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006117 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01006118 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6119 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01006120 { } /* end */
6121};
6122
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006123/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
6124 * versions of the ALC260 don't act on requests to enable mic bias from NID
6125 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
6126 * datasheet doesn't mention this restriction. At this stage it's not clear
6127 * whether this behaviour is intentional or is a hardware bug in chip
6128 * revisions available in early 2006. Therefore for now allow the
6129 * "Headphone Jack Mode" control to span all choices, but if it turns out
6130 * that the lack of mic bias for this NID is intentional we could change the
6131 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
6132 *
6133 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
6134 * don't appear to make the mic bias available from the "line" jack, even
6135 * though the NID used for this jack (0x14) can supply it. The theory is
6136 * that perhaps Acer have included blocking capacitors between the ALC260
6137 * and the output jack. If this turns out to be the case for all such
6138 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
6139 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01006140 *
6141 * The C20x Tablet series have a mono internal speaker which is controlled
6142 * via the chip's Mono sum widget and pin complex, so include the necessary
6143 * controls for such models. On models without a "mono speaker" the control
6144 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006145 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006146static struct snd_kcontrol_new alc260_acer_mixer[] = {
6147 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6148 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006149 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01006150 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01006151 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01006152 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01006153 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006154 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6155 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
6156 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6157 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6158 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6159 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6160 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6161 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006162 { } /* end */
6163};
6164
Michael Schwingencc959482009-02-22 18:58:45 +01006165/* Maxdata Favorit 100XS: one output and one input (0x12) jack
6166 */
6167static struct snd_kcontrol_new alc260_favorit100_mixer[] = {
6168 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6169 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
6170 ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
6171 HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6172 HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6173 ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6174 { } /* end */
6175};
6176
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006177/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
6178 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
6179 */
6180static struct snd_kcontrol_new alc260_will_mixer[] = {
6181 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6182 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
6183 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6184 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6185 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6186 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6187 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6188 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
6189 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6190 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006191 { } /* end */
6192};
6193
6194/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
6195 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
6196 */
6197static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
6198 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6199 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
6200 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6201 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6202 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6203 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
6204 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
6205 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6206 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6207 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
6208 { } /* end */
6209};
6210
Kailang Yangdf694da2005-12-05 19:42:22 +01006211/*
6212 * initialization verbs
6213 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006214static struct hda_verb alc260_init_verbs[] = {
6215 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006216 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006217 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006218 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006219 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006220 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006221 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006222 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006223 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02006224 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006225 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01006226 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006227 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02006228 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006229 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02006230 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006231 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02006232 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6233 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02006234 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006235 /* set connection select to line in (default select for this ADC) */
6236 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02006237 /* mute capture amp left and right */
6238 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6239 /* set connection select to line in (default select for this ADC) */
6240 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02006241 /* set vol=0 Line-Out mixer amp left and right */
6242 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6243 /* unmute pin widget amp left and right (no gain on this amp) */
6244 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6245 /* set vol=0 HP mixer amp left and right */
6246 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6247 /* unmute pin widget amp left and right (no gain on this amp) */
6248 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6249 /* set vol=0 Mono mixer amp left and right */
6250 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6251 /* unmute pin widget amp left and right (no gain on this amp) */
6252 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6253 /* unmute LINE-2 out pin */
6254 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006255 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6256 * Line In 2 = 0x03
6257 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006258 /* mute analog inputs */
6259 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6260 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6261 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6262 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6263 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006264 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02006265 /* mute Front out path */
6266 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6267 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6268 /* mute Headphone out path */
6269 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6270 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6271 /* mute Mono out path */
6272 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6273 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006274 { }
6275};
6276
Takashi Iwai474167d2006-05-17 17:17:43 +02006277#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01006278static struct hda_verb alc260_hp_init_verbs[] = {
6279 /* Headphone and output */
6280 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
6281 /* mono output */
6282 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6283 /* Mic1 (rear panel) pin widget for input and vref at 80% */
6284 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6285 /* Mic2 (front panel) pin widget for input and vref at 80% */
6286 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6287 /* Line In pin widget for input */
6288 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6289 /* Line-2 pin widget for output */
6290 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6291 /* CD pin widget for input */
6292 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6293 /* unmute amp left and right */
6294 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
6295 /* set connection select to line in (default select for this ADC) */
6296 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
6297 /* unmute Line-Out mixer amp left and right (volume = 0) */
6298 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6299 /* mute pin widget amp left and right (no gain on this amp) */
6300 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
6301 /* unmute HP mixer amp left and right (volume = 0) */
6302 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6303 /* mute pin widget amp left and right (no gain on this amp) */
6304 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006305 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6306 * Line In 2 = 0x03
6307 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006308 /* mute analog inputs */
6309 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6310 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6311 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6312 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6313 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006314 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
6315 /* Unmute Front out path */
6316 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6317 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6318 /* Unmute Headphone out path */
6319 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6320 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6321 /* Unmute Mono out path */
6322 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6323 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6324 { }
6325};
Takashi Iwai474167d2006-05-17 17:17:43 +02006326#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01006327
6328static struct hda_verb alc260_hp_3013_init_verbs[] = {
6329 /* Line out and output */
6330 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6331 /* mono output */
6332 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6333 /* Mic1 (rear panel) pin widget for input and vref at 80% */
6334 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6335 /* Mic2 (front panel) pin widget for input and vref at 80% */
6336 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6337 /* Line In pin widget for input */
6338 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6339 /* Headphone pin widget for output */
6340 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
6341 /* CD pin widget for input */
6342 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6343 /* unmute amp left and right */
6344 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
6345 /* set connection select to line in (default select for this ADC) */
6346 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
6347 /* unmute Line-Out mixer amp left and right (volume = 0) */
6348 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6349 /* mute pin widget amp left and right (no gain on this amp) */
6350 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
6351 /* unmute HP mixer amp left and right (volume = 0) */
6352 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6353 /* mute pin widget amp left and right (no gain on this amp) */
6354 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006355 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6356 * Line In 2 = 0x03
6357 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006358 /* mute analog inputs */
6359 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6360 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6361 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6362 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6363 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006364 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
6365 /* Unmute Front out path */
6366 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6367 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6368 /* Unmute Headphone out path */
6369 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6370 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6371 /* Unmute Mono out path */
6372 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6373 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6374 { }
6375};
6376
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006377/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006378 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
6379 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006380 */
6381static struct hda_verb alc260_fujitsu_init_verbs[] = {
6382 /* Disable all GPIOs */
6383 {0x01, AC_VERB_SET_GPIO_MASK, 0},
6384 /* Internal speaker is connected to headphone pin */
6385 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6386 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
6387 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006388 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
6389 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6390 /* Ensure all other unused pins are disabled and muted. */
6391 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6392 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006393 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006394 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006395 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006396 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6397 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6398 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006399
Jonathan Woithef7ace402006-02-28 11:46:14 +01006400 /* Disable digital (SPDIF) pins */
6401 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6402 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006403
Kailang Yangea1fb292008-08-26 12:58:38 +02006404 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
Jonathan Woithef7ace402006-02-28 11:46:14 +01006405 * when acting as an output.
6406 */
6407 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6408
6409 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01006410 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6411 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6412 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6413 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6414 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6415 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6416 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6417 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6418 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006419
Jonathan Woithef7ace402006-02-28 11:46:14 +01006420 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
6421 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6422 /* Unmute Line1 pin widget output buffer since it starts as an output.
6423 * If the pin mode is changed by the user the pin mode control will
6424 * take care of enabling the pin's input/output buffers as needed.
6425 * Therefore there's no need to enable the input buffer at this
6426 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006427 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01006428 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +02006429 /* Unmute input buffer of pin widget used for Line-in (no equiv
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006430 * mixer ctrl)
6431 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01006432 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006433
Jonathan Woithef7ace402006-02-28 11:46:14 +01006434 /* Mute capture amp left and right */
6435 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006436 /* Set ADC connection select to match default mixer setting - line
Jonathan Woithef7ace402006-02-28 11:46:14 +01006437 * in (on mic1 pin)
6438 */
6439 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006440
Jonathan Woithef7ace402006-02-28 11:46:14 +01006441 /* Do the same for the second ADC: mute capture input amp and
6442 * set ADC connection to line in (on mic1 pin)
6443 */
6444 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6445 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006446
Jonathan Woithef7ace402006-02-28 11:46:14 +01006447 /* Mute all inputs to mixer widget (even unconnected ones) */
6448 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6449 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6450 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6451 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6452 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6453 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6454 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6455 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01006456
6457 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006458};
6459
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006460/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
6461 * similar laptops (adapted from Fujitsu init verbs).
6462 */
6463static struct hda_verb alc260_acer_init_verbs[] = {
6464 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
6465 * the headphone jack. Turn this on and rely on the standard mute
6466 * methods whenever the user wants to turn these outputs off.
6467 */
6468 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6469 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6470 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
6471 /* Internal speaker/Headphone jack is connected to Line-out pin */
6472 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6473 /* Internal microphone/Mic jack is connected to Mic1 pin */
6474 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
6475 /* Line In jack is connected to Line1 pin */
6476 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01006477 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
6478 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006479 /* Ensure all other unused pins are disabled and muted. */
6480 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6481 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006482 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6483 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6484 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6485 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6486 /* Disable digital (SPDIF) pins */
6487 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6488 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6489
Kailang Yangea1fb292008-08-26 12:58:38 +02006490 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006491 * bus when acting as outputs.
6492 */
6493 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6494 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6495
6496 /* Start with output sum widgets muted and their output gains at min */
6497 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6498 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6499 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6500 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6501 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6502 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6503 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6504 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6505 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6506
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006507 /* Unmute Line-out pin widget amp left and right
6508 * (no equiv mixer ctrl)
6509 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006510 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01006511 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
6512 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006513 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
6514 * inputs. If the pin mode is changed by the user the pin mode control
6515 * will take care of enabling the pin's input/output buffers as needed.
6516 * Therefore there's no need to enable the input buffer at this
6517 * stage.
6518 */
6519 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6520 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6521
6522 /* Mute capture amp left and right */
6523 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6524 /* Set ADC connection select to match default mixer setting - mic
6525 * (on mic1 pin)
6526 */
6527 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6528
6529 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006530 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006531 */
6532 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006533 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006534
6535 /* Mute all inputs to mixer widget (even unconnected ones) */
6536 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6537 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6538 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6539 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6540 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6541 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6542 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6543 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6544
6545 { }
6546};
6547
Michael Schwingencc959482009-02-22 18:58:45 +01006548/* Initialisation sequence for Maxdata Favorit 100XS
6549 * (adapted from Acer init verbs).
6550 */
6551static struct hda_verb alc260_favorit100_init_verbs[] = {
6552 /* GPIO 0 enables the output jack.
6553 * Turn this on and rely on the standard mute
6554 * methods whenever the user wants to turn these outputs off.
6555 */
6556 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6557 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6558 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
6559 /* Line/Mic input jack is connected to Mic1 pin */
6560 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
6561 /* Ensure all other unused pins are disabled and muted. */
6562 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6563 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6564 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6565 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6566 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6567 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6568 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6569 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6570 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6571 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6572 /* Disable digital (SPDIF) pins */
6573 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6574 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6575
6576 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
6577 * bus when acting as outputs.
6578 */
6579 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6580 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6581
6582 /* Start with output sum widgets muted and their output gains at min */
6583 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6584 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6585 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6586 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6587 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6588 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6589 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6590 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6591 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6592
6593 /* Unmute Line-out pin widget amp left and right
6594 * (no equiv mixer ctrl)
6595 */
6596 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6597 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
6598 * inputs. If the pin mode is changed by the user the pin mode control
6599 * will take care of enabling the pin's input/output buffers as needed.
6600 * Therefore there's no need to enable the input buffer at this
6601 * stage.
6602 */
6603 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6604
6605 /* Mute capture amp left and right */
6606 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6607 /* Set ADC connection select to match default mixer setting - mic
6608 * (on mic1 pin)
6609 */
6610 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6611
6612 /* Do similar with the second ADC: mute capture input amp and
6613 * set ADC connection to mic to match ALSA's default state.
6614 */
6615 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6616 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6617
6618 /* Mute all inputs to mixer widget (even unconnected ones) */
6619 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6620 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6621 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6622 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6623 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6624 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6625 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6626 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6627
6628 { }
6629};
6630
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006631static struct hda_verb alc260_will_verbs[] = {
6632 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6633 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
6634 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
6635 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
6636 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
6637 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
6638 {}
6639};
6640
6641static struct hda_verb alc260_replacer_672v_verbs[] = {
6642 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
6643 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
6644 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
6645
6646 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6647 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6648 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6649
6650 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6651 {}
6652};
6653
6654/* toggle speaker-output according to the hp-jack state */
6655static void alc260_replacer_672v_automute(struct hda_codec *codec)
6656{
6657 unsigned int present;
6658
6659 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
Wu Fengguang864f92b2009-11-18 12:38:02 +08006660 present = snd_hda_jack_detect(codec, 0x0f);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006661 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006662 snd_hda_codec_write_cache(codec, 0x01, 0,
6663 AC_VERB_SET_GPIO_DATA, 1);
6664 snd_hda_codec_write_cache(codec, 0x0f, 0,
6665 AC_VERB_SET_PIN_WIDGET_CONTROL,
6666 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006667 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006668 snd_hda_codec_write_cache(codec, 0x01, 0,
6669 AC_VERB_SET_GPIO_DATA, 0);
6670 snd_hda_codec_write_cache(codec, 0x0f, 0,
6671 AC_VERB_SET_PIN_WIDGET_CONTROL,
6672 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006673 }
6674}
6675
6676static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
6677 unsigned int res)
6678{
6679 if ((res >> 26) == ALC880_HP_EVENT)
6680 alc260_replacer_672v_automute(codec);
6681}
6682
Kailang Yang3f878302008-08-26 13:02:23 +02006683static struct hda_verb alc260_hp_dc7600_verbs[] = {
6684 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
6685 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
6686 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6687 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6688 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6689 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6690 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6691 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6692 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6693 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6694 {}
6695};
6696
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006697/* Test configuration for debugging, modelled after the ALC880 test
6698 * configuration.
6699 */
6700#ifdef CONFIG_SND_DEBUG
6701static hda_nid_t alc260_test_dac_nids[1] = {
6702 0x02,
6703};
6704static hda_nid_t alc260_test_adc_nids[2] = {
6705 0x04, 0x05,
6706};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006707/* For testing the ALC260, each input MUX needs its own definition since
Kailang Yangea1fb292008-08-26 12:58:38 +02006708 * the signal assignments are different. This assumes that the first ADC
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006709 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01006710 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006711static struct hda_input_mux alc260_test_capture_sources[2] = {
6712 {
6713 .num_items = 7,
6714 .items = {
6715 { "MIC1 pin", 0x0 },
6716 { "MIC2 pin", 0x1 },
6717 { "LINE1 pin", 0x2 },
6718 { "LINE2 pin", 0x3 },
6719 { "CD pin", 0x4 },
6720 { "LINE-OUT pin", 0x5 },
6721 { "HP-OUT pin", 0x6 },
6722 },
6723 },
6724 {
6725 .num_items = 8,
6726 .items = {
6727 { "MIC1 pin", 0x0 },
6728 { "MIC2 pin", 0x1 },
6729 { "LINE1 pin", 0x2 },
6730 { "LINE2 pin", 0x3 },
6731 { "CD pin", 0x4 },
6732 { "Mixer", 0x5 },
6733 { "LINE-OUT pin", 0x6 },
6734 { "HP-OUT pin", 0x7 },
6735 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006736 },
6737};
6738static struct snd_kcontrol_new alc260_test_mixer[] = {
6739 /* Output driver widgets */
6740 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
6741 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
6742 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6743 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
6744 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6745 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
6746
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006747 /* Modes for retasking pin widgets
6748 * Note: the ALC260 doesn't seem to act on requests to enable mic
6749 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
6750 * mention this restriction. At this stage it's not clear whether
6751 * this behaviour is intentional or is a hardware bug in chip
6752 * revisions available at least up until early 2006. Therefore for
6753 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
6754 * choices, but if it turns out that the lack of mic bias for these
6755 * NIDs is intentional we could change their modes from
6756 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
6757 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006758 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
6759 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
6760 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
6761 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
6762 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
6763 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
6764
6765 /* Loopback mixer controls */
6766 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
6767 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
6768 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
6769 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
6770 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
6771 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
6772 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
6773 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
6774 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6775 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006776 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
6777 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
6778 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
6779 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01006780
6781 /* Controls for GPIO pins, assuming they are configured as outputs */
6782 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
6783 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
6784 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
6785 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
6786
Jonathan Woithe92621f12006-02-28 11:47:47 +01006787 /* Switches to allow the digital IO pins to be enabled. The datasheet
6788 * is ambigious as to which NID is which; testing on laptops which
Kailang Yangea1fb292008-08-26 12:58:38 +02006789 * make this output available should provide clarification.
Jonathan Woithe92621f12006-02-28 11:47:47 +01006790 */
6791 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
6792 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
6793
Jonathan Woithef8225f62008-01-08 12:16:54 +01006794 /* A switch allowing EAPD to be enabled. Some laptops seem to use
6795 * this output to turn on an external amplifier.
6796 */
6797 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
6798 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
6799
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006800 { } /* end */
6801};
6802static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01006803 /* Enable all GPIOs as outputs with an initial value of 0 */
6804 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
6805 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6806 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
6807
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006808 /* Enable retasking pins as output, initially without power amp */
6809 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6810 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6811 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6812 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6813 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6814 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6815
Jonathan Woithe92621f12006-02-28 11:47:47 +01006816 /* Disable digital (SPDIF) pins initially, but users can enable
6817 * them via a mixer switch. In the case of SPDIF-out, this initverb
6818 * payload also sets the generation to 0, output to be in "consumer"
6819 * PCM format, copyright asserted, no pre-emphasis and no validity
6820 * control.
6821 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006822 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6823 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6824
Kailang Yangea1fb292008-08-26 12:58:38 +02006825 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006826 * OUT1 sum bus when acting as an output.
6827 */
6828 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6829 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
6830 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6831 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
6832
6833 /* Start with output sum widgets muted and their output gains at min */
6834 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6835 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6836 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6837 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6838 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6839 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6840 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6841 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6842 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6843
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006844 /* Unmute retasking pin widget output buffers since the default
6845 * state appears to be output. As the pin mode is changed by the
6846 * user the pin mode control will take care of enabling the pin's
6847 * input/output buffers as needed.
6848 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006849 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6850 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6851 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6852 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6853 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6854 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6855 /* Also unmute the mono-out pin widget */
6856 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6857
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006858 /* Mute capture amp left and right */
6859 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006860 /* Set ADC connection select to match default mixer setting (mic1
6861 * pin)
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006862 */
6863 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6864
6865 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01006866 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006867 */
6868 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6869 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6870
6871 /* Mute all inputs to mixer widget (even unconnected ones) */
6872 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6873 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6874 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6875 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6876 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6877 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6878 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6879 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6880
6881 { }
6882};
6883#endif
6884
Takashi Iwai63300792008-01-24 15:31:36 +01006885#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
6886#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07006887
Takashi Iwaia3bcba32005-12-06 19:05:29 +01006888#define alc260_pcm_digital_playback alc880_pcm_digital_playback
6889#define alc260_pcm_digital_capture alc880_pcm_digital_capture
6890
Kailang Yangdf694da2005-12-05 19:42:22 +01006891/*
6892 * for BIOS auto-configuration
6893 */
6894
6895static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai863b4512008-10-21 17:01:47 +02006896 const char *pfx, int *vol_bits)
Kailang Yangdf694da2005-12-05 19:42:22 +01006897{
6898 hda_nid_t nid_vol;
6899 unsigned long vol_val, sw_val;
Kailang Yangdf694da2005-12-05 19:42:22 +01006900 int err;
6901
6902 if (nid >= 0x0f && nid < 0x11) {
6903 nid_vol = nid - 0x7;
6904 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
6905 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
6906 } else if (nid == 0x11) {
6907 nid_vol = nid - 0x7;
6908 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
6909 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
6910 } else if (nid >= 0x12 && nid <= 0x15) {
6911 nid_vol = 0x08;
6912 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
6913 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
6914 } else
6915 return 0; /* N/A */
Kailang Yangea1fb292008-08-26 12:58:38 +02006916
Takashi Iwai863b4512008-10-21 17:01:47 +02006917 if (!(*vol_bits & (1 << nid_vol))) {
6918 /* first control for the volume widget */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02006919 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, vol_val);
Takashi Iwai863b4512008-10-21 17:01:47 +02006920 if (err < 0)
6921 return err;
6922 *vol_bits |= (1 << nid_vol);
6923 }
Takashi Iwai0afe5f82009-10-02 09:20:00 +02006924 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, sw_val);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006925 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006926 return err;
6927 return 1;
6928}
6929
6930/* add playback controls from the parsed DAC table */
6931static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
6932 const struct auto_pin_cfg *cfg)
6933{
6934 hda_nid_t nid;
6935 int err;
Takashi Iwai863b4512008-10-21 17:01:47 +02006936 int vols = 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01006937
6938 spec->multiout.num_dacs = 1;
6939 spec->multiout.dac_nids = spec->private_dac_nids;
6940 spec->multiout.dac_nids[0] = 0x02;
6941
6942 nid = cfg->line_out_pins[0];
6943 if (nid) {
Takashi Iwai23112d62009-08-25 16:07:08 +02006944 const char *pfx;
6945 if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
6946 pfx = "Master";
6947 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
6948 pfx = "Speaker";
6949 else
6950 pfx = "Front";
6951 err = alc260_add_playback_controls(spec, nid, pfx, &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006952 if (err < 0)
6953 return err;
6954 }
6955
Takashi Iwai82bc9552006-03-21 11:24:42 +01006956 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006957 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02006958 err = alc260_add_playback_controls(spec, nid, "Speaker", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006959 if (err < 0)
6960 return err;
6961 }
6962
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006963 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006964 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02006965 err = alc260_add_playback_controls(spec, nid, "Headphone",
6966 &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006967 if (err < 0)
6968 return err;
6969 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006970 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01006971}
6972
6973/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +02006974static int alc260_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yangdf694da2005-12-05 19:42:22 +01006975 const struct auto_pin_cfg *cfg)
6976{
Takashi Iwai05f5f472009-08-25 13:10:18 +02006977 return alc_auto_create_input_ctls(codec, cfg, 0x07, 0x04, 0x05);
Kailang Yangdf694da2005-12-05 19:42:22 +01006978}
6979
6980static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
6981 hda_nid_t nid, int pin_type,
6982 int sel_idx)
6983{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006984 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006985 /* need the manual connection? */
6986 if (nid >= 0x12) {
6987 int idx = nid - 0x12;
6988 snd_hda_codec_write(codec, idx + 0x0b, 0,
6989 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01006990 }
6991}
6992
6993static void alc260_auto_init_multi_out(struct hda_codec *codec)
6994{
6995 struct alc_spec *spec = codec->spec;
6996 hda_nid_t nid;
6997
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006998 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006999 if (nid) {
7000 int pin_type = get_pin_type(spec->autocfg.line_out_type);
7001 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
7002 }
Kailang Yangea1fb292008-08-26 12:58:38 +02007003
Takashi Iwai82bc9552006-03-21 11:24:42 +01007004 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007005 if (nid)
7006 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
7007
Takashi Iwaieb06ed82006-09-20 17:10:27 +02007008 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007009 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007010 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007011}
Kailang Yangdf694da2005-12-05 19:42:22 +01007012
7013#define ALC260_PIN_CD_NID 0x16
7014static void alc260_auto_init_analog_input(struct hda_codec *codec)
7015{
7016 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02007017 struct auto_pin_cfg *cfg = &spec->autocfg;
Kailang Yangdf694da2005-12-05 19:42:22 +01007018 int i;
7019
Takashi Iwai66ceeb62010-08-30 13:05:52 +02007020 for (i = 0; i < cfg->num_inputs; i++) {
7021 hda_nid_t nid = cfg->inputs[i].pin;
Kailang Yangdf694da2005-12-05 19:42:22 +01007022 if (nid >= 0x12) {
Takashi Iwai30ea0982010-09-16 18:47:56 +02007023 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwaie82c0252009-03-23 15:17:38 +01007024 if (nid != ALC260_PIN_CD_NID &&
7025 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007026 snd_hda_codec_write(codec, nid, 0,
7027 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01007028 AMP_OUT_MUTE);
7029 }
7030 }
7031}
7032
Takashi Iwai7f311a42010-04-09 17:32:23 +02007033#define alc260_auto_init_input_src alc880_auto_init_input_src
7034
Kailang Yangdf694da2005-12-05 19:42:22 +01007035/*
7036 * generic initialization of ADC, input mixers and output mixers
7037 */
7038static struct hda_verb alc260_volume_init_verbs[] = {
7039 /*
7040 * Unmute ADC0-1 and set the default input to mic-in
7041 */
7042 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
7043 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7044 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
7045 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02007046
Kailang Yangdf694da2005-12-05 19:42:22 +01007047 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
7048 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007049 * Note: PASD motherboards uses the Line In 2 as the input for
7050 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01007051 */
7052 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02007053 /* mute analog inputs */
7054 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7055 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7056 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7057 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7058 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01007059
7060 /*
7061 * Set up output mixers (0x08 - 0x0a)
7062 */
7063 /* set vol=0 to output mixers */
7064 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7065 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7066 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7067 /* set up input amps for analog loopback */
7068 /* Amp Indices: DAC = 0, mixer = 1 */
7069 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7070 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7071 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7072 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7073 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7074 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +02007075
Kailang Yangdf694da2005-12-05 19:42:22 +01007076 { }
7077};
7078
7079static int alc260_parse_auto_config(struct hda_codec *codec)
7080{
7081 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007082 int err;
7083 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
7084
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007085 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
7086 alc260_ignore);
7087 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01007088 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007089 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
7090 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01007091 return err;
Takashi Iwai603c4012008-07-30 15:01:44 +02007092 if (!spec->kctls.list)
Kailang Yangdf694da2005-12-05 19:42:22 +01007093 return 0; /* can't find valid BIOS pin config */
Takashi Iwai05f5f472009-08-25 13:10:18 +02007094 err = alc260_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007095 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01007096 return err;
7097
7098 spec->multiout.max_channels = 2;
7099
Takashi Iwai0852d7a2009-02-11 11:35:15 +01007100 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +01007101 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
Takashi Iwai603c4012008-07-30 15:01:44 +02007102 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01007103 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +01007104
Takashi Iwaid88897e2008-10-31 15:01:37 +01007105 add_verb(spec, alc260_volume_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +01007106
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007107 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02007108 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007109
Kailang Yang6227cdc2010-02-25 08:36:52 +01007110 alc_ssid_check(codec, 0x10, 0x15, 0x0f, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02007111
Kailang Yangdf694da2005-12-05 19:42:22 +01007112 return 1;
7113}
7114
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007115/* additional initialization for auto-configuration model */
7116static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01007117{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007118 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007119 alc260_auto_init_multi_out(codec);
7120 alc260_auto_init_analog_input(codec);
Takashi Iwai7f311a42010-04-09 17:32:23 +02007121 alc260_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +02007122 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007123 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02007124 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01007125}
7126
Takashi Iwaicb53c622007-08-10 17:21:45 +02007127#ifdef CONFIG_SND_HDA_POWER_SAVE
7128static struct hda_amp_list alc260_loopbacks[] = {
7129 { 0x07, HDA_INPUT, 0 },
7130 { 0x07, HDA_INPUT, 1 },
7131 { 0x07, HDA_INPUT, 2 },
7132 { 0x07, HDA_INPUT, 3 },
7133 { 0x07, HDA_INPUT, 4 },
7134 { } /* end */
7135};
7136#endif
7137
Kailang Yangdf694da2005-12-05 19:42:22 +01007138/*
Takashi Iwaifc091762010-08-04 23:53:36 +02007139 * Pin config fixes
7140 */
7141enum {
7142 PINFIX_HP_DC5750,
7143};
7144
Takashi Iwaifc091762010-08-04 23:53:36 +02007145static const struct alc_fixup alc260_fixups[] = {
7146 [PINFIX_HP_DC5750] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01007147 .type = ALC_FIXUP_PINS,
7148 .v.pins = (const struct alc_pincfg[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +02007149 { 0x11, 0x90130110 }, /* speaker */
7150 { }
7151 }
Takashi Iwaifc091762010-08-04 23:53:36 +02007152 },
7153};
7154
7155static struct snd_pci_quirk alc260_fixup_tbl[] = {
7156 SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750),
7157 {}
7158};
7159
7160/*
Kailang Yangdf694da2005-12-05 19:42:22 +01007161 * ALC260 configurations
7162 */
Takashi Iwaiea734962011-01-17 11:29:34 +01007163static const char * const alc260_models[ALC260_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007164 [ALC260_BASIC] = "basic",
7165 [ALC260_HP] = "hp",
7166 [ALC260_HP_3013] = "hp-3013",
Takashi Iwai2922c9a2008-08-27 18:12:42 +02007167 [ALC260_HP_DC7600] = "hp-dc7600",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007168 [ALC260_FUJITSU_S702X] = "fujitsu",
7169 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007170 [ALC260_WILL] = "will",
7171 [ALC260_REPLACER_672V] = "replacer",
Michael Schwingencc959482009-02-22 18:58:45 +01007172 [ALC260_FAVORIT100] = "favorit100",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007173#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007174 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007175#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007176 [ALC260_AUTO] = "auto",
7177};
7178
7179static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01007180 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Daniel T Chen950200e2009-12-13 14:11:02 -05007181 SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007182 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Michael Schwingencc959482009-02-22 18:58:45 +01007183 SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100),
Takashi Iwai9720b712007-03-13 21:46:23 +01007184 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwai4ac55982009-11-10 16:08:45 +01007185 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007186 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
Jaroslav Kysela34ec8a02008-07-10 14:49:19 +02007187 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
Kailang Yang3f878302008-08-26 13:02:23 +02007188 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007189 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
7190 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
7191 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
7192 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
7193 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
7194 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
7195 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
7196 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
7197 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007198 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007199 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02007200 {}
7201};
7202
Kailang Yangdf694da2005-12-05 19:42:22 +01007203static struct alc_config_preset alc260_presets[] = {
7204 [ALC260_BASIC] = {
7205 .mixers = { alc260_base_output_mixer,
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007206 alc260_input_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01007207 .init_verbs = { alc260_init_verbs },
7208 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7209 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007210 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
Takashi Iwai9c4cc0b2010-03-15 09:07:52 +01007211 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01007212 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7213 .channel_mode = alc260_modes,
7214 .input_mux = &alc260_capture_source,
7215 },
7216 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01007217 .mixers = { alc260_hp_output_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007218 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01007219 .init_verbs = { alc260_init_verbs,
7220 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01007221 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7222 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007223 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7224 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01007225 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7226 .channel_mode = alc260_modes,
7227 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01007228 .unsol_event = alc260_hp_unsol_event,
7229 .init_hook = alc260_hp_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01007230 },
Kailang Yang3f878302008-08-26 13:02:23 +02007231 [ALC260_HP_DC7600] = {
7232 .mixers = { alc260_hp_dc7600_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007233 alc260_input_mixer },
Kailang Yang3f878302008-08-26 13:02:23 +02007234 .init_verbs = { alc260_init_verbs,
7235 alc260_hp_dc7600_verbs },
7236 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7237 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007238 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7239 .adc_nids = alc260_adc_nids_alt,
Kailang Yang3f878302008-08-26 13:02:23 +02007240 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7241 .channel_mode = alc260_modes,
7242 .input_mux = &alc260_capture_source,
7243 .unsol_event = alc260_hp_3012_unsol_event,
7244 .init_hook = alc260_hp_3012_automute,
7245 },
Kailang Yangdf694da2005-12-05 19:42:22 +01007246 [ALC260_HP_3013] = {
7247 .mixers = { alc260_hp_3013_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007248 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01007249 .init_verbs = { alc260_hp_3013_init_verbs,
7250 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01007251 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7252 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007253 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7254 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01007255 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7256 .channel_mode = alc260_modes,
7257 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01007258 .unsol_event = alc260_hp_3013_unsol_event,
7259 .init_hook = alc260_hp_3013_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01007260 },
7261 [ALC260_FUJITSU_S702X] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007262 .mixers = { alc260_fujitsu_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01007263 .init_verbs = { alc260_fujitsu_init_verbs },
7264 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7265 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01007266 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7267 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01007268 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7269 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007270 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
7271 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01007272 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007273 [ALC260_ACER] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007274 .mixers = { alc260_acer_mixer },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007275 .init_verbs = { alc260_acer_init_verbs },
7276 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7277 .dac_nids = alc260_dac_nids,
7278 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7279 .adc_nids = alc260_dual_adc_nids,
7280 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7281 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007282 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
7283 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007284 },
Michael Schwingencc959482009-02-22 18:58:45 +01007285 [ALC260_FAVORIT100] = {
7286 .mixers = { alc260_favorit100_mixer },
7287 .init_verbs = { alc260_favorit100_init_verbs },
7288 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7289 .dac_nids = alc260_dac_nids,
7290 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7291 .adc_nids = alc260_dual_adc_nids,
7292 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7293 .channel_mode = alc260_modes,
7294 .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources),
7295 .input_mux = alc260_favorit100_capture_sources,
7296 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007297 [ALC260_WILL] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007298 .mixers = { alc260_will_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007299 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
7300 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7301 .dac_nids = alc260_dac_nids,
7302 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
7303 .adc_nids = alc260_adc_nids,
7304 .dig_out_nid = ALC260_DIGOUT_NID,
7305 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7306 .channel_mode = alc260_modes,
7307 .input_mux = &alc260_capture_source,
7308 },
7309 [ALC260_REPLACER_672V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007310 .mixers = { alc260_replacer_672v_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007311 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
7312 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7313 .dac_nids = alc260_dac_nids,
7314 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
7315 .adc_nids = alc260_adc_nids,
7316 .dig_out_nid = ALC260_DIGOUT_NID,
7317 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7318 .channel_mode = alc260_modes,
7319 .input_mux = &alc260_capture_source,
7320 .unsol_event = alc260_replacer_672v_unsol_event,
7321 .init_hook = alc260_replacer_672v_automute,
7322 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007323#ifdef CONFIG_SND_DEBUG
7324 [ALC260_TEST] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007325 .mixers = { alc260_test_mixer },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007326 .init_verbs = { alc260_test_init_verbs },
7327 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
7328 .dac_nids = alc260_test_dac_nids,
7329 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
7330 .adc_nids = alc260_test_adc_nids,
7331 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7332 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007333 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
7334 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007335 },
7336#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01007337};
7338
Linus Torvalds1da177e2005-04-16 15:20:36 -07007339static int patch_alc260(struct hda_codec *codec)
7340{
7341 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007342 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007343
Takashi Iwaie560d8d2005-09-09 14:21:46 +02007344 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007345 if (spec == NULL)
7346 return -ENOMEM;
7347
7348 codec->spec = spec;
7349
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007350 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
7351 alc260_models,
7352 alc260_cfg_tbl);
7353 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02007354 snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai6c627f32009-05-18 12:33:36 +02007355 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +01007356 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02007357 }
7358
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01007359 if (board_config == ALC260_AUTO) {
7360 alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups);
7361 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
7362 }
Takashi Iwaifc091762010-08-04 23:53:36 +02007363
Kailang Yangdf694da2005-12-05 19:42:22 +01007364 if (board_config == ALC260_AUTO) {
7365 /* automatic parse from the BIOS config */
7366 err = alc260_parse_auto_config(codec);
7367 if (err < 0) {
7368 alc_free(codec);
7369 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007370 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007371 printk(KERN_INFO
7372 "hda_codec: Cannot set up configuration "
7373 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01007374 board_config = ALC260_BASIC;
7375 }
Takashi Iwai16ded522005-06-10 19:58:24 +02007376 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007377
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09007378 err = snd_hda_attach_beep_device(codec, 0x1);
7379 if (err < 0) {
7380 alc_free(codec);
7381 return err;
7382 }
7383
Kailang Yangdf694da2005-12-05 19:42:22 +01007384 if (board_config != ALC260_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02007385 setup_preset(codec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007386
Linus Torvalds1da177e2005-04-16 15:20:36 -07007387 spec->stream_analog_playback = &alc260_pcm_analog_playback;
7388 spec->stream_analog_capture = &alc260_pcm_analog_capture;
Jonathan Woithe53bacfb2010-08-08 00:17:05 +09307389 spec->stream_analog_alt_capture = &alc260_pcm_analog_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007390
Takashi Iwaia3bcba32005-12-06 19:05:29 +01007391 spec->stream_digital_playback = &alc260_pcm_digital_playback;
7392 spec->stream_digital_capture = &alc260_pcm_digital_capture;
7393
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01007394 if (!spec->adc_nids && spec->input_mux) {
7395 /* check whether NID 0x04 is valid */
7396 unsigned int wcap = get_wcaps(codec, 0x04);
Takashi Iwaia22d5432009-07-27 12:54:26 +02007397 wcap = get_wcaps_type(wcap);
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01007398 /* get type */
7399 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
7400 spec->adc_nids = alc260_adc_nids_alt;
7401 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
7402 } else {
7403 spec->adc_nids = alc260_adc_nids;
7404 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
7405 }
7406 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02007407 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007408 set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007409
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01007410 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwaifc091762010-08-04 23:53:36 +02007411
Takashi Iwai2134ea42008-01-10 16:53:55 +01007412 spec->vmaster_nid = 0x08;
7413
Linus Torvalds1da177e2005-04-16 15:20:36 -07007414 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01007415 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007416 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02007417#ifdef CONFIG_SND_HDA_POWER_SAVE
7418 if (!spec->loopback.amplist)
7419 spec->loopback.amplist = alc260_loopbacks;
7420#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007421
7422 return 0;
7423}
7424
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007425
Linus Torvalds1da177e2005-04-16 15:20:36 -07007426/*
Takashi Iwai49535502009-06-30 15:28:30 +02007427 * ALC882/883/885/888/889 support
Linus Torvalds1da177e2005-04-16 15:20:36 -07007428 *
7429 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
7430 * configuration. Each pin widget can choose any input DACs and a mixer.
7431 * Each ADC is connected from a mixer of all inputs. This makes possible
7432 * 6-channel independent captures.
7433 *
7434 * In addition, an independent DAC for the multi-playback (not used in this
7435 * driver yet).
7436 */
Kailang Yangdf694da2005-12-05 19:42:22 +01007437#define ALC882_DIGOUT_NID 0x06
7438#define ALC882_DIGIN_NID 0x0a
Takashi Iwai49535502009-06-30 15:28:30 +02007439#define ALC883_DIGOUT_NID ALC882_DIGOUT_NID
7440#define ALC883_DIGIN_NID ALC882_DIGIN_NID
7441#define ALC1200_DIGOUT_NID 0x10
7442
Linus Torvalds1da177e2005-04-16 15:20:36 -07007443
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01007444static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007445 { 8, NULL }
7446};
7447
Takashi Iwai49535502009-06-30 15:28:30 +02007448/* DACs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007449static hda_nid_t alc882_dac_nids[4] = {
7450 /* front, rear, clfe, rear_surr */
7451 0x02, 0x03, 0x04, 0x05
7452};
Takashi Iwai49535502009-06-30 15:28:30 +02007453#define alc883_dac_nids alc882_dac_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007454
Takashi Iwai49535502009-06-30 15:28:30 +02007455/* ADCs */
Kailang Yangdf694da2005-12-05 19:42:22 +01007456#define alc882_adc_nids alc880_adc_nids
7457#define alc882_adc_nids_alt alc880_adc_nids_alt
Takashi Iwai49535502009-06-30 15:28:30 +02007458#define alc883_adc_nids alc882_adc_nids_alt
7459static hda_nid_t alc883_adc_nids_alt[1] = { 0x08 };
7460static hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 };
7461#define alc889_adc_nids alc880_adc_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007462
Takashi Iwaie1406342008-02-11 18:32:32 +01007463static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
7464static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
Takashi Iwai49535502009-06-30 15:28:30 +02007465#define alc883_capsrc_nids alc882_capsrc_nids_alt
7466static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
7467#define alc889_capsrc_nids alc882_capsrc_nids
Takashi Iwaie1406342008-02-11 18:32:32 +01007468
Linus Torvalds1da177e2005-04-16 15:20:36 -07007469/* input MUX */
7470/* FIXME: should be a matrix-type input source selection */
7471
7472static struct hda_input_mux alc882_capture_source = {
7473 .num_items = 4,
7474 .items = {
7475 { "Mic", 0x0 },
7476 { "Front Mic", 0x1 },
7477 { "Line", 0x2 },
7478 { "CD", 0x4 },
7479 },
7480};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007481
Takashi Iwai49535502009-06-30 15:28:30 +02007482#define alc883_capture_source alc882_capture_source
7483
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007484static struct hda_input_mux alc889_capture_source = {
7485 .num_items = 3,
7486 .items = {
7487 { "Front Mic", 0x0 },
7488 { "Mic", 0x3 },
7489 { "Line", 0x2 },
7490 },
7491};
7492
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007493static struct hda_input_mux mb5_capture_source = {
7494 .num_items = 3,
7495 .items = {
7496 { "Mic", 0x1 },
Alex Murrayb8f171e2010-06-14 12:08:43 +09307497 { "Line", 0x7 },
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007498 { "CD", 0x4 },
7499 },
7500};
7501
Luke Yelaviche458b1f2010-02-12 16:28:29 +11007502static struct hda_input_mux macmini3_capture_source = {
7503 .num_items = 2,
7504 .items = {
7505 { "Line", 0x2 },
7506 { "CD", 0x4 },
7507 },
7508};
7509
Takashi Iwai49535502009-06-30 15:28:30 +02007510static struct hda_input_mux alc883_3stack_6ch_intel = {
7511 .num_items = 4,
7512 .items = {
7513 { "Mic", 0x1 },
7514 { "Front Mic", 0x0 },
7515 { "Line", 0x2 },
7516 { "CD", 0x4 },
7517 },
7518};
7519
7520static struct hda_input_mux alc883_lenovo_101e_capture_source = {
7521 .num_items = 2,
7522 .items = {
7523 { "Mic", 0x1 },
7524 { "Line", 0x2 },
7525 },
7526};
7527
7528static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
7529 .num_items = 4,
7530 .items = {
7531 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +01007532 { "Internal Mic", 0x1 },
Takashi Iwai49535502009-06-30 15:28:30 +02007533 { "Line", 0x2 },
7534 { "CD", 0x4 },
7535 },
7536};
7537
7538static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
7539 .num_items = 2,
7540 .items = {
7541 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +01007542 { "Internal Mic", 0x1 },
Takashi Iwai49535502009-06-30 15:28:30 +02007543 },
7544};
7545
7546static struct hda_input_mux alc883_lenovo_sky_capture_source = {
7547 .num_items = 3,
7548 .items = {
7549 { "Mic", 0x0 },
7550 { "Front Mic", 0x1 },
7551 { "Line", 0x4 },
7552 },
7553};
7554
7555static struct hda_input_mux alc883_asus_eee1601_capture_source = {
7556 .num_items = 2,
7557 .items = {
7558 { "Mic", 0x0 },
7559 { "Line", 0x2 },
7560 },
7561};
7562
7563static struct hda_input_mux alc889A_mb31_capture_source = {
7564 .num_items = 2,
7565 .items = {
7566 { "Mic", 0x0 },
7567 /* Front Mic (0x01) unused */
7568 { "Line", 0x2 },
7569 /* Line 2 (0x03) unused */
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02007570 /* CD (0x04) unused? */
Takashi Iwai49535502009-06-30 15:28:30 +02007571 },
7572};
7573
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07007574static struct hda_input_mux alc889A_imac91_capture_source = {
7575 .num_items = 2,
7576 .items = {
7577 { "Mic", 0x01 },
7578 { "Line", 0x2 }, /* Not sure! */
7579 },
7580};
7581
Takashi Iwai49535502009-06-30 15:28:30 +02007582/*
7583 * 2ch mode
7584 */
7585static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
7586 { 2, NULL }
7587};
7588
Kailang Yangdf694da2005-12-05 19:42:22 +01007589/*
Kailang Yang272a5272007-05-14 11:00:38 +02007590 * 2ch mode
7591 */
7592static struct hda_verb alc882_3ST_ch2_init[] = {
7593 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7594 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7595 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7596 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7597 { } /* end */
7598};
7599
7600/*
Takashi Iwai49535502009-06-30 15:28:30 +02007601 * 4ch mode
7602 */
7603static struct hda_verb alc882_3ST_ch4_init[] = {
7604 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7605 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7606 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7607 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7608 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7609 { } /* end */
7610};
7611
7612/*
Kailang Yang272a5272007-05-14 11:00:38 +02007613 * 6ch mode
7614 */
7615static struct hda_verb alc882_3ST_ch6_init[] = {
7616 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7617 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7618 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7619 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7620 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7621 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7622 { } /* end */
7623};
7624
Takashi Iwai49535502009-06-30 15:28:30 +02007625static struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
Kailang Yang272a5272007-05-14 11:00:38 +02007626 { 2, alc882_3ST_ch2_init },
Takashi Iwai49535502009-06-30 15:28:30 +02007627 { 4, alc882_3ST_ch4_init },
Kailang Yang272a5272007-05-14 11:00:38 +02007628 { 6, alc882_3ST_ch6_init },
7629};
7630
Takashi Iwai49535502009-06-30 15:28:30 +02007631#define alc883_3ST_6ch_modes alc882_3ST_6ch_modes
7632
Kailang Yang272a5272007-05-14 11:00:38 +02007633/*
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307634 * 2ch mode
7635 */
7636static struct hda_verb alc883_3ST_ch2_clevo_init[] = {
7637 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
7638 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7639 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7640 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7641 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7642 { } /* end */
7643};
7644
7645/*
7646 * 4ch mode
7647 */
7648static struct hda_verb alc883_3ST_ch4_clevo_init[] = {
7649 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7650 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7651 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7652 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7653 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7654 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7655 { } /* end */
7656};
7657
7658/*
7659 * 6ch mode
7660 */
7661static struct hda_verb alc883_3ST_ch6_clevo_init[] = {
7662 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7663 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7664 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7665 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7666 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7667 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7668 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7669 { } /* end */
7670};
7671
7672static struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
7673 { 2, alc883_3ST_ch2_clevo_init },
7674 { 4, alc883_3ST_ch4_clevo_init },
7675 { 6, alc883_3ST_ch6_clevo_init },
7676};
7677
7678
7679/*
Kailang Yangdf694da2005-12-05 19:42:22 +01007680 * 6ch mode
7681 */
7682static struct hda_verb alc882_sixstack_ch6_init[] = {
7683 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7684 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7685 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7686 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7687 { } /* end */
7688};
7689
7690/*
7691 * 8ch mode
7692 */
7693static struct hda_verb alc882_sixstack_ch8_init[] = {
7694 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7695 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7696 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7697 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7698 { } /* end */
7699};
7700
7701static struct hda_channel_mode alc882_sixstack_modes[2] = {
7702 { 6, alc882_sixstack_ch6_init },
7703 { 8, alc882_sixstack_ch8_init },
7704};
7705
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08007706
7707/* Macbook Air 2,1 */
7708
7709static struct hda_channel_mode alc885_mba21_ch_modes[1] = {
7710 { 2, NULL },
7711};
7712
Takashi Iwai87350ad2007-08-16 18:19:38 +02007713/*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04007714 * macbook pro ALC885 can switch LineIn to LineOut without losing Mic
Takashi Iwai87350ad2007-08-16 18:19:38 +02007715 */
7716
7717/*
7718 * 2ch mode
7719 */
7720static struct hda_verb alc885_mbp_ch2_init[] = {
7721 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7722 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7723 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7724 { } /* end */
7725};
7726
7727/*
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007728 * 4ch mode
Takashi Iwai87350ad2007-08-16 18:19:38 +02007729 */
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007730static struct hda_verb alc885_mbp_ch4_init[] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007731 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7732 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7733 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7734 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7735 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7736 { } /* end */
7737};
7738
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007739static struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007740 { 2, alc885_mbp_ch2_init },
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007741 { 4, alc885_mbp_ch4_init },
Takashi Iwai87350ad2007-08-16 18:19:38 +02007742};
7743
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007744/*
7745 * 2ch
7746 * Speakers/Woofer/HP = Front
7747 * LineIn = Input
7748 */
7749static struct hda_verb alc885_mb5_ch2_init[] = {
7750 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7751 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7752 { } /* end */
7753};
7754
7755/*
7756 * 6ch mode
7757 * Speakers/HP = Front
7758 * Woofer = LFE
7759 * LineIn = Surround
7760 */
7761static struct hda_verb alc885_mb5_ch6_init[] = {
7762 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7763 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7764 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7765 { } /* end */
7766};
7767
7768static struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
7769 { 2, alc885_mb5_ch2_init },
7770 { 6, alc885_mb5_ch6_init },
7771};
Takashi Iwai87350ad2007-08-16 18:19:38 +02007772
Takashi Iwaid01aecd2010-02-23 08:07:15 +01007773#define alc885_macmini3_6ch_modes alc885_mb5_6ch_modes
Takashi Iwai49535502009-06-30 15:28:30 +02007774
7775/*
7776 * 2ch mode
7777 */
7778static struct hda_verb alc883_4ST_ch2_init[] = {
7779 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7780 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7781 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7782 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7783 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7784 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7785 { } /* end */
7786};
7787
7788/*
7789 * 4ch mode
7790 */
7791static struct hda_verb alc883_4ST_ch4_init[] = {
7792 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7793 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7794 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7795 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7796 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7797 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7798 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7799 { } /* end */
7800};
7801
7802/*
7803 * 6ch mode
7804 */
7805static struct hda_verb alc883_4ST_ch6_init[] = {
7806 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7807 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7808 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7809 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7810 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7811 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7812 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7813 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7814 { } /* end */
7815};
7816
7817/*
7818 * 8ch mode
7819 */
7820static struct hda_verb alc883_4ST_ch8_init[] = {
7821 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7822 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7823 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7824 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7825 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7826 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7827 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7828 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7829 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7830 { } /* end */
7831};
7832
7833static struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
7834 { 2, alc883_4ST_ch2_init },
7835 { 4, alc883_4ST_ch4_init },
7836 { 6, alc883_4ST_ch6_init },
7837 { 8, alc883_4ST_ch8_init },
7838};
7839
7840
7841/*
7842 * 2ch mode
7843 */
7844static struct hda_verb alc883_3ST_ch2_intel_init[] = {
7845 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7846 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7847 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7848 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7849 { } /* end */
7850};
7851
7852/*
7853 * 4ch mode
7854 */
7855static struct hda_verb alc883_3ST_ch4_intel_init[] = {
7856 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7857 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7858 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7859 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7860 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7861 { } /* end */
7862};
7863
7864/*
7865 * 6ch mode
7866 */
7867static struct hda_verb alc883_3ST_ch6_intel_init[] = {
7868 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7869 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7870 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
7871 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7872 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7873 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7874 { } /* end */
7875};
7876
7877static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
7878 { 2, alc883_3ST_ch2_intel_init },
7879 { 4, alc883_3ST_ch4_intel_init },
7880 { 6, alc883_3ST_ch6_intel_init },
7881};
7882
7883/*
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007884 * 2ch mode
7885 */
7886static struct hda_verb alc889_ch2_intel_init[] = {
7887 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7888 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 },
7889 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 },
7890 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00 },
7891 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7892 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7893 { } /* end */
7894};
7895
7896/*
Takashi Iwai49535502009-06-30 15:28:30 +02007897 * 6ch mode
7898 */
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007899static struct hda_verb alc889_ch6_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007900 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7901 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7902 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7903 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7904 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007905 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7906 { } /* end */
7907};
7908
7909/*
7910 * 8ch mode
7911 */
7912static struct hda_verb alc889_ch8_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007913 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7914 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7915 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7916 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7917 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x03 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007918 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7919 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007920 { } /* end */
7921};
7922
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007923static struct hda_channel_mode alc889_8ch_intel_modes[3] = {
7924 { 2, alc889_ch2_intel_init },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007925 { 6, alc889_ch6_intel_init },
7926 { 8, alc889_ch8_intel_init },
7927};
7928
7929/*
7930 * 6ch mode
7931 */
Takashi Iwai49535502009-06-30 15:28:30 +02007932static struct hda_verb alc883_sixstack_ch6_init[] = {
7933 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7934 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7935 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7936 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7937 { } /* end */
7938};
7939
7940/*
7941 * 8ch mode
7942 */
7943static struct hda_verb alc883_sixstack_ch8_init[] = {
7944 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7945 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7946 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7947 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7948 { } /* end */
7949};
7950
7951static struct hda_channel_mode alc883_sixstack_modes[2] = {
7952 { 6, alc883_sixstack_ch6_init },
7953 { 8, alc883_sixstack_ch8_init },
7954};
7955
7956
Linus Torvalds1da177e2005-04-16 15:20:36 -07007957/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
7958 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
7959 */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01007960static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02007961 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007962 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007963 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007964 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007965 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7966 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007967 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7968 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007969 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007970 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007971 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7972 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7973 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7974 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7975 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7976 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01007977 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007978 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7979 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01007980 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007981 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007982 { } /* end */
7983};
7984
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08007985/* Macbook Air 2,1 same control for HP and internal Speaker */
7986
7987static struct snd_kcontrol_new alc885_mba21_mixer[] = {
7988 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7989 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT),
7990 { }
7991};
7992
7993
Takashi Iwai87350ad2007-08-16 18:19:38 +02007994static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007995 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7996 HDA_BIND_MUTE ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
7997 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7998 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT),
7999 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01008000 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8001 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02008002 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
8003 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008004 HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT),
8005 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02008006 { } /* end */
8007};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008008
8009static struct snd_kcontrol_new alc885_mb5_mixer[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008010 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8011 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
8012 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
8013 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
8014 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
8015 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
Alex Murraya76221d2010-01-13 23:15:03 +10308016 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
8017 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
Alex Murrayb8f171e2010-06-14 12:08:43 +09308018 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
8019 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008020 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8021 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008022 HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT),
8023 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0x00, HDA_INPUT),
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008024 { } /* end */
8025};
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008026
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008027static struct snd_kcontrol_new alc885_macmini3_mixer[] = {
8028 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8029 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
8030 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
8031 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
8032 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
8033 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
8034 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
8035 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
8036 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
8037 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008038 HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT),
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008039 { } /* end */
8040};
8041
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008042static struct snd_kcontrol_new alc885_imac91_mixer[] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008043 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8044 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008045 { } /* end */
8046};
8047
8048
Kailang Yangbdd148a2007-05-08 15:19:08 +02008049static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
8050 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8051 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8052 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8053 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8054 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8055 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8056 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008057 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02008058 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02008059 { } /* end */
8060};
8061
Kailang Yang272a5272007-05-14 11:00:38 +02008062static struct snd_kcontrol_new alc882_targa_mixer[] = {
8063 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8064 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8065 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8066 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8067 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8068 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8069 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8070 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8071 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008072 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008073 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8074 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008075 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008076 { } /* end */
8077};
8078
8079/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
8080 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
8081 */
8082static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
8083 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8084 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8085 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8086 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
8087 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8088 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8089 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8090 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8091 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
8092 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
8093 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8094 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008095 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008096 { } /* end */
8097};
8098
Takashi Iwai914759b2007-09-06 14:52:04 +02008099static struct snd_kcontrol_new alc882_asus_a7m_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", 0x15, 0x0, HDA_OUTPUT),
8103 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8104 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8105 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8106 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8107 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008108 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02008109 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02008110 { } /* end */
8111};
8112
Kailang Yangdf694da2005-12-05 19:42:22 +01008113static struct snd_kcontrol_new alc882_chmode_mixer[] = {
8114 {
8115 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8116 .name = "Channel Mode",
8117 .info = alc_ch_mode_info,
8118 .get = alc_ch_mode_get,
8119 .put = alc_ch_mode_put,
8120 },
8121 { } /* end */
8122};
8123
Takashi Iwai49535502009-06-30 15:28:30 +02008124static struct hda_verb alc882_base_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008125 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008126 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8127 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008128 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02008129 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8130 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008131 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02008132 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8133 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008134 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02008135 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8136 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008137
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008138 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008139 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008140 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008141 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008142 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008143 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008144 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008145 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008146 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008147 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008148 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008149 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008150 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008151 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008152 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008153 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008154 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02008155 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008156 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8157 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02008158 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008159 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8160 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02008161 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008162 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8163 /* Line-2 In: Headphone output (output 0 - 0x0c) */
8164 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8165 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8166 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008167 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02008168 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008169
8170 /* FIXME: use matrix-type input source selection */
8171 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008172 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02008173 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008174 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02008175 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai05acb862005-06-10 19:50:25 +02008176 /* ADC2: mute amp left and right */
8177 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02008178 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02008179 /* ADC3: mute amp left and right */
8180 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02008181 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008182
8183 { }
8184};
8185
Takashi Iwai49535502009-06-30 15:28:30 +02008186static struct hda_verb alc882_adc1_init_verbs[] = {
8187 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8188 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8189 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8190 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8191 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8192 /* ADC1: mute amp left and right */
8193 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8194 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8195 { }
8196};
8197
Takashi Iwai4b146cb2006-07-28 14:42:36 +02008198static struct hda_verb alc882_eapd_verbs[] = {
8199 /* change to EAPD mode */
8200 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008201 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008202 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02008203};
8204
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008205static struct hda_verb alc889_eapd_verbs[] = {
8206 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
8207 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
8208 { }
8209};
8210
Wu Fengguang6732bd02009-07-30 09:19:14 +02008211static struct hda_verb alc_hp15_unsol_verbs[] = {
8212 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8213 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8214 {}
8215};
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008216
8217static struct hda_verb alc885_init_verbs[] = {
8218 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Kailang Yang88102f32010-02-04 14:12:58 +01008219 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8220 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008221 /* Rear mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008222 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8223 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008224 /* CLFE mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008225 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8226 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008227 /* Side mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008228 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8229 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008230
8231 /* Front HP Pin: output 0 (0x0c) */
Wu Fengguang6732bd02009-07-30 09:19:14 +02008232 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008233 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8234 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8235 /* Front Pin: output 0 (0x0c) */
8236 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8237 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8238 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8239 /* Rear Pin: output 1 (0x0d) */
8240 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8241 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8242 {0x19, AC_VERB_SET_CONNECT_SEL, 0x01},
8243 /* CLFE Pin: output 2 (0x0e) */
8244 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8245 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8246 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
8247 /* Side Pin: output 3 (0x0f) */
8248 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8249 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8250 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
8251 /* Mic (rear) pin: input vref at 80% */
8252 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8253 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8254 /* Front Mic pin: input vref at 80% */
8255 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8256 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8257 /* Line In pin: input */
8258 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8259 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8260
8261 /* Mixer elements: 0x18, , 0x1a, 0x1b */
8262 /* Input mixer1 */
Kailang Yang88102f32010-02-04 14:12:58 +01008263 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008264 /* Input mixer2 */
8265 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008266 /* Input mixer3 */
Kailang Yang88102f32010-02-04 14:12:58 +01008267 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008268 /* ADC2: mute amp left and right */
8269 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8270 /* ADC3: mute amp left and right */
8271 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8272
8273 { }
8274};
8275
8276static struct hda_verb alc885_init_input_verbs[] = {
8277 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8278 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
8279 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
8280 { }
8281};
8282
8283
8284/* Unmute Selector 24h and set the default input to front mic */
8285static struct hda_verb alc889_init_input_verbs[] = {
8286 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
8287 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8288 { }
8289};
8290
8291
Takashi Iwai49535502009-06-30 15:28:30 +02008292#define alc883_init_verbs alc882_base_init_verbs
8293
Tobin Davis9102cd12006-12-15 10:02:12 +01008294/* Mac Pro test */
8295static struct snd_kcontrol_new alc882_macpro_mixer[] = {
8296 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8297 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8298 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
8299 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
8300 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01008301 /* FIXME: this looks suspicious...
Jaroslav Kyselad355c82a2009-11-03 15:47:25 +01008302 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT),
8303 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01008304 */
Tobin Davis9102cd12006-12-15 10:02:12 +01008305 { } /* end */
8306};
8307
8308static struct hda_verb alc882_macpro_init_verbs[] = {
8309 /* Front mixer: unmute input/output amp left and right (volume = 0) */
8310 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8311 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8312 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8313 /* Front Pin: output 0 (0x0c) */
8314 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8315 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8316 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8317 /* Front Mic pin: input vref at 80% */
8318 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8319 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8320 /* Speaker: output */
8321 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8322 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8323 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
8324 /* Headphone output (output 0 - 0x0c) */
8325 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8326 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8327 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8328
8329 /* FIXME: use matrix-type input source selection */
8330 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8331 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8332 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8333 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8334 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8335 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8336 /* Input mixer2 */
8337 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8338 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8339 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8340 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8341 /* Input mixer3 */
8342 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8343 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8344 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8345 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8346 /* ADC1: mute amp left and right */
8347 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8348 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8349 /* ADC2: mute amp left and right */
8350 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8351 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8352 /* ADC3: mute amp left and right */
8353 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8354 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8355
8356 { }
8357};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008358
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008359/* Macbook 5,1 */
8360static struct hda_verb alc885_mb5_init_verbs[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008361 /* DACs */
8362 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8363 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8364 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8365 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008366 /* Front mixer */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008367 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8368 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8369 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008370 /* Surround mixer */
8371 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8372 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8373 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8374 /* LFE mixer */
8375 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8376 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8377 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8378 /* HP mixer */
8379 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8380 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8381 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8382 /* Front Pin (0x0c) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008383 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8384 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008385 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8386 /* LFE Pin (0x0e) */
8387 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8388 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8389 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
8390 /* HP Pin (0x0f) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008391 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8392 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008393 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
Alex Murraya76221d2010-01-13 23:15:03 +10308394 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008395 /* Front Mic pin: input vref at 80% */
8396 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8397 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8398 /* Line In pin */
8399 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8400 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8401
Alex Murrayb8f171e2010-06-14 12:08:43 +09308402 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0x1)},
8403 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x7)},
8404 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x4)},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008405 { }
8406};
8407
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008408/* Macmini 3,1 */
8409static struct hda_verb alc885_macmini3_init_verbs[] = {
8410 /* DACs */
8411 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8412 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8413 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8414 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8415 /* Front mixer */
8416 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8417 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8418 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8419 /* Surround mixer */
8420 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8421 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8422 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8423 /* LFE mixer */
8424 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8425 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8426 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8427 /* HP mixer */
8428 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8429 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8430 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8431 /* Front Pin (0x0c) */
8432 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8433 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8434 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8435 /* LFE Pin (0x0e) */
8436 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8437 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8438 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
8439 /* HP Pin (0x0f) */
8440 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8441 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8442 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
8443 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8444 /* Line In pin */
8445 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8446 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8447
8448 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8449 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8450 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8451 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8452 { }
8453};
8454
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008455
8456static struct hda_verb alc885_mba21_init_verbs[] = {
8457 /*Internal and HP Speaker Mixer*/
8458 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8459 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8460 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8461 /*Internal Speaker Pin (0x0c)*/
8462 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8463 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8464 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8465 /* HP Pin: output 0 (0x0e) */
8466 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
8467 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8468 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8469 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
8470 /* Line in (is hp when jack connected)*/
8471 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
8472 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8473
8474 { }
8475 };
8476
8477
Takashi Iwai87350ad2007-08-16 18:19:38 +02008478/* Macbook Pro rev3 */
8479static struct hda_verb alc885_mbp3_init_verbs[] = {
8480 /* Front mixer: unmute input/output amp left and right (volume = 0) */
8481 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8482 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8483 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8484 /* Rear mixer */
8485 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8486 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8487 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008488 /* HP mixer */
8489 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8490 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8491 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai87350ad2007-08-16 18:19:38 +02008492 /* Front Pin: output 0 (0x0c) */
8493 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8494 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8495 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008496 /* HP Pin: output 0 (0x0e) */
Takashi Iwai87350ad2007-08-16 18:19:38 +02008497 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008498 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8499 {0x15, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai87350ad2007-08-16 18:19:38 +02008500 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8501 /* Mic (rear) pin: input vref at 80% */
8502 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8503 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8504 /* Front Mic pin: input vref at 80% */
8505 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8506 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8507 /* Line In pin: use output 1 when in LineOut mode */
8508 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8509 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8510 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
8511
8512 /* FIXME: use matrix-type input source selection */
8513 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8514 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8515 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8516 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8517 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8518 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8519 /* Input mixer2 */
8520 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8521 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8522 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8523 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8524 /* Input mixer3 */
8525 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8526 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8527 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8528 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8529 /* ADC1: mute amp left and right */
8530 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8531 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8532 /* ADC2: mute amp left and right */
8533 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8534 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8535 /* ADC3: mute amp left and right */
8536 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8537 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8538
8539 { }
8540};
8541
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008542/* iMac 9,1 */
8543static struct hda_verb alc885_imac91_init_verbs[] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008544 /* Internal Speaker Pin (0x0c) */
8545 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8546 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8547 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8548 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8549 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8550 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8551 /* HP Pin: Rear */
8552 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8553 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8554 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8555 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
8556 /* Line in Rear */
8557 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
8558 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8559 /* Front Mic pin: input vref at 80% */
8560 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8561 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008562 /* Rear mixer */
8563 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8564 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8565 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008566 /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */
8567 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8568 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8569 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8570 /* 0x24 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008571 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8572 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8573 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8574 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008575 /* 0x23 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008576 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8577 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8578 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8579 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008580 /* 0x22 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008581 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8582 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8583 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8584 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008585 /* 0x07 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008586 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8587 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008588 /* 0x08 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008589 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8590 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008591 /* 0x09 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008592 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8593 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008594 { }
8595};
8596
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008597/* iMac 24 mixer. */
8598static struct snd_kcontrol_new alc885_imac24_mixer[] = {
8599 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8600 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
8601 { } /* end */
8602};
8603
8604/* iMac 24 init verbs. */
8605static struct hda_verb alc885_imac24_init_verbs[] = {
8606 /* Internal speakers: output 0 (0x0c) */
8607 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8608 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8609 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8610 /* Internal speakers: output 0 (0x0c) */
8611 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8612 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8613 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8614 /* Headphone: output 0 (0x0c) */
8615 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8616 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8617 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8618 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8619 /* Front Mic: input vref at 80% */
8620 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8621 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8622 { }
8623};
8624
8625/* Toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008626static void alc885_imac24_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008627{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008628 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008629
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008630 spec->autocfg.hp_pins[0] = 0x14;
8631 spec->autocfg.speaker_pins[0] = 0x18;
8632 spec->autocfg.speaker_pins[1] = 0x1a;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008633}
8634
Takashi Iwai9d54f082010-02-22 08:34:40 +01008635#define alc885_mb5_setup alc885_imac24_setup
8636#define alc885_macmini3_setup alc885_imac24_setup
8637
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008638/* Macbook Air 2,1 */
8639static void alc885_mba21_setup(struct hda_codec *codec)
8640{
8641 struct alc_spec *spec = codec->spec;
8642
8643 spec->autocfg.hp_pins[0] = 0x14;
8644 spec->autocfg.speaker_pins[0] = 0x18;
8645}
8646
8647
8648
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008649static void alc885_mbp3_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008650{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008651 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008652
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008653 spec->autocfg.hp_pins[0] = 0x15;
8654 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai87350ad2007-08-16 18:19:38 +02008655}
8656
Takashi Iwai9d54f082010-02-22 08:34:40 +01008657static void alc885_imac91_setup(struct hda_codec *codec)
Alex Murraya76221d2010-01-13 23:15:03 +10308658{
Takashi Iwai9d54f082010-02-22 08:34:40 +01008659 struct alc_spec *spec = codec->spec;
Alex Murraya76221d2010-01-13 23:15:03 +10308660
Takashi Iwai9d54f082010-02-22 08:34:40 +01008661 spec->autocfg.hp_pins[0] = 0x14;
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008662 spec->autocfg.speaker_pins[0] = 0x18;
Takashi Iwai9d54f082010-02-22 08:34:40 +01008663 spec->autocfg.speaker_pins[1] = 0x1a;
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008664}
Takashi Iwai87350ad2007-08-16 18:19:38 +02008665
Kailang Yang272a5272007-05-14 11:00:38 +02008666static struct hda_verb alc882_targa_verbs[] = {
8667 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8668 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8669
8670 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8671 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008672
Kailang Yang272a5272007-05-14 11:00:38 +02008673 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8674 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8675 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8676
8677 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yang272a5272007-05-14 11:00:38 +02008678 { } /* end */
8679};
8680
8681/* toggle speaker-output according to the hp-jack state */
8682static void alc882_targa_automute(struct hda_codec *codec)
8683{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008684 struct alc_spec *spec = codec->spec;
8685 alc_automute_amp(codec);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02008686 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008687 spec->jack_present ? 1 : 3);
8688}
8689
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008690static void alc882_targa_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008691{
8692 struct alc_spec *spec = codec->spec;
8693
8694 spec->autocfg.hp_pins[0] = 0x14;
8695 spec->autocfg.speaker_pins[0] = 0x1b;
Kailang Yang272a5272007-05-14 11:00:38 +02008696}
8697
8698static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
8699{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008700 if ((res >> 26) == ALC880_HP_EVENT)
Kailang Yang272a5272007-05-14 11:00:38 +02008701 alc882_targa_automute(codec);
Kailang Yang272a5272007-05-14 11:00:38 +02008702}
8703
8704static struct hda_verb alc882_asus_a7j_verbs[] = {
8705 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8706 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8707
8708 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8709 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8710 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008711
Kailang Yang272a5272007-05-14 11:00:38 +02008712 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8713 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8714 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8715
8716 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8717 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8718 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8719 { } /* end */
8720};
8721
Takashi Iwai914759b2007-09-06 14:52:04 +02008722static struct hda_verb alc882_asus_a7m_verbs[] = {
8723 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8724 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8725
8726 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8727 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8728 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008729
Takashi Iwai914759b2007-09-06 14:52:04 +02008730 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8731 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8732 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8733
8734 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8735 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8736 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8737 { } /* end */
8738};
8739
Tobin Davis9102cd12006-12-15 10:02:12 +01008740static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
8741{
8742 unsigned int gpiostate, gpiomask, gpiodir;
8743
8744 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
8745 AC_VERB_GET_GPIO_DATA, 0);
8746
8747 if (!muted)
8748 gpiostate |= (1 << pin);
8749 else
8750 gpiostate &= ~(1 << pin);
8751
8752 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
8753 AC_VERB_GET_GPIO_MASK, 0);
8754 gpiomask |= (1 << pin);
8755
8756 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
8757 AC_VERB_GET_GPIO_DIRECTION, 0);
8758 gpiodir |= (1 << pin);
8759
8760
8761 snd_hda_codec_write(codec, codec->afg, 0,
8762 AC_VERB_SET_GPIO_MASK, gpiomask);
8763 snd_hda_codec_write(codec, codec->afg, 0,
8764 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
8765
8766 msleep(1);
8767
8768 snd_hda_codec_write(codec, codec->afg, 0,
8769 AC_VERB_SET_GPIO_DATA, gpiostate);
8770}
8771
Takashi Iwai7debbe52007-08-16 15:01:03 +02008772/* set up GPIO at initialization */
8773static void alc885_macpro_init_hook(struct hda_codec *codec)
8774{
8775 alc882_gpio_mute(codec, 0, 0);
8776 alc882_gpio_mute(codec, 1, 0);
8777}
8778
8779/* set up GPIO and update auto-muting at initialization */
8780static void alc885_imac24_init_hook(struct hda_codec *codec)
8781{
8782 alc885_macpro_init_hook(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008783 alc_automute_amp(codec);
Takashi Iwai7debbe52007-08-16 15:01:03 +02008784}
8785
Kailang Yangdf694da2005-12-05 19:42:22 +01008786/*
8787 * generic initialization of ADC, input mixers and output mixers
8788 */
Takashi Iwai49535502009-06-30 15:28:30 +02008789static struct hda_verb alc883_auto_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01008790 /*
8791 * Unmute ADC0-2 and set the default input to mic-in
8792 */
Kailang Yangdf694da2005-12-05 19:42:22 +01008793 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8794 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8795 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8796 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8797
Kailang Yangdf694da2005-12-05 19:42:22 +01008798 /*
8799 * Set up output mixers (0x0c - 0x0f)
8800 */
8801 /* set vol=0 to output mixers */
8802 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8803 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8804 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8805 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8806 /* set up input amps for analog loopback */
8807 /* Amp Indices: DAC = 0, mixer = 1 */
8808 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8809 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8810 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8811 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8812 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8813 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8814 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8815 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8816 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8817 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8818
8819 /* FIXME: use matrix-type input source selection */
8820 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Kailang Yangdf694da2005-12-05 19:42:22 +01008821 /* Input mixer2 */
Kailang Yang88102f32010-02-04 14:12:58 +01008822 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008823 /* Input mixer3 */
Kailang Yang88102f32010-02-04 14:12:58 +01008824 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008825 { }
8826};
8827
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008828/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
8829static struct hda_verb alc889A_mb31_ch2_init[] = {
8830 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
8831 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8832 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
8833 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
8834 { } /* end */
8835};
8836
8837/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */
8838static struct hda_verb alc889A_mb31_ch4_init[] = {
8839 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
8840 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8841 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
8842 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
8843 { } /* end */
8844};
8845
8846/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */
8847static struct hda_verb alc889A_mb31_ch5_init[] = {
8848 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */
8849 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8850 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
8851 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
8852 { } /* end */
8853};
8854
8855/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */
8856static struct hda_verb alc889A_mb31_ch6_init[] = {
8857 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */
8858 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */
8859 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
8860 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
8861 { } /* end */
8862};
8863
8864static struct hda_channel_mode alc889A_mb31_6ch_modes[4] = {
8865 { 2, alc889A_mb31_ch2_init },
8866 { 4, alc889A_mb31_ch4_init },
8867 { 5, alc889A_mb31_ch5_init },
8868 { 6, alc889A_mb31_ch6_init },
8869};
8870
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008871static struct hda_verb alc883_medion_eapd_verbs[] = {
8872 /* eanable EAPD on medion laptop */
8873 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8874 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
8875 { }
8876};
8877
Takashi Iwai49535502009-06-30 15:28:30 +02008878#define alc883_base_mixer alc882_base_mixer
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008879
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008880static struct snd_kcontrol_new alc883_mitac_mixer[] = {
8881 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8882 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8883 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8884 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8885 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8886 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8887 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8888 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008889 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008890 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8891 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008892 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008893 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008894 { } /* end */
8895};
8896
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008897static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01008898 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8899 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8900 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8901 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8902 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008903 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01008904 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01008905 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008906 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01008907 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01008908 { } /* end */
8909};
8910
Jiang zhefb97dc62008-03-06 11:07:11 +01008911static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
8912 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8913 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8914 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8915 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8916 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008917 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01008918 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01008919 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008920 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01008921 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01008922 { } /* end */
8923};
8924
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008925static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
8926 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8927 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8928 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8929 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8930 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8931 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8932 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8933 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008934 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008935 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8936 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008937 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008938 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008939 { } /* end */
8940};
8941
8942static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
8943 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8944 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8945 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8946 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8947 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8948 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8949 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8950 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8951 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8952 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8953 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8954 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8955 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8956 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008957 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008958 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8959 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008960 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008961 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008962 { } /* end */
8963};
8964
Jiang zhe17bba1b2008-06-04 12:11:07 +02008965static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
8966 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8967 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8968 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8969 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8970 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
8971 HDA_OUTPUT),
8972 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8973 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8974 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8975 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8976 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8977 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8978 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8979 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8980 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008981 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008982 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8983 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008984 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008985 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008986 { } /* end */
8987};
8988
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008989static struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
8990 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8991 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8992 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8993 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8994 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
8995 HDA_OUTPUT),
8996 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8997 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8998 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8999 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
9000 HDA_BIND_MUTE("Speaker Playback Switch", 0x0f, 2, HDA_INPUT),
9001 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9002 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9003 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9004 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009005 HDA_CODEC_VOLUME("Mic Boost Volume", 0x1b, 0, HDA_INPUT),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009006 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
9007 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009008 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009009 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9010 { } /* end */
9011};
9012
Takashi Iwaid1d985f2006-11-23 19:27:12 +01009013static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02009014 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02009015 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009016 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02009017 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009018 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
9019 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02009020 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9021 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009022 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9023 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9024 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9025 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9026 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9027 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009028 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009029 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9030 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009031 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009032 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009033 { } /* end */
9034};
9035
Sasha Alexandrc2592492009-06-16 14:52:54 -04009036static struct snd_kcontrol_new alc883_targa_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02009037 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009038 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009039 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009040 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009041 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9042 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
9043 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
9044 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
9045 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9046 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
9047 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9048 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9049 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9050 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9051 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009052 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009053 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009054 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009055};
Kailang Yangccc656c2006-10-17 12:32:26 +02009056
Sasha Alexandrc2592492009-06-16 14:52:54 -04009057static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02009058 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009059 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009060 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009061 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009062 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9063 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9064 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009065 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009066 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009067 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009068 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009069 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009070 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009071};
Kailang Yangccc656c2006-10-17 12:32:26 +02009072
Takashi Iwaib99dba32009-09-17 18:23:00 +02009073static struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
9074 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
9075 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009076 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009077 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009078 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009079 { } /* end */
9080};
9081
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009082static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
9083 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9084 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01009085 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9086 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009087 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9088 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009089 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009090 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009091 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009092};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009093
Kailang Yang272a5272007-05-14 11:00:38 +02009094static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
9095 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9096 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
9097 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9098 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9099 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9100 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9101 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009102 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
9103 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02009104 { } /* end */
Kailang Yangea1fb292008-08-26 12:58:38 +02009105};
Kailang Yang272a5272007-05-14 11:00:38 +02009106
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009107static struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = {
9108 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9109 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9110 HDA_CODEC_MUTE("Speaker Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9111 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
9112 HDA_CODEC_VOLUME("Line Playback Volume", 0x08, 0x0, HDA_INPUT),
9113 HDA_CODEC_MUTE("Line Playback Switch", 0x08, 0x0, HDA_INPUT),
9114 { } /* end */
9115};
9116
9117static struct hda_verb alc883_medion_wim2160_verbs[] = {
9118 /* Unmute front mixer */
9119 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9120 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9121
9122 /* Set speaker pin to front mixer */
9123 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9124
9125 /* Init headphone pin */
9126 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9127 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9128 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
9129 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9130
9131 { } /* end */
9132};
9133
9134/* toggle speaker-output according to the hp-jack state */
9135static void alc883_medion_wim2160_setup(struct hda_codec *codec)
9136{
9137 struct alc_spec *spec = codec->spec;
9138
9139 spec->autocfg.hp_pins[0] = 0x1a;
9140 spec->autocfg.speaker_pins[0] = 0x15;
9141}
9142
Tobin Davis2880a862007-08-07 11:50:26 +02009143static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02009144 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9145 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02009146 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02009147 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9148 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02009149 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009150 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02009151 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02009152 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02009153};
Tobin Davis2880a862007-08-07 11:50:26 +02009154
Tony Vroond2fd4b02009-06-21 00:40:10 +01009155static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
9156 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01009157 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Tony Vroon684a8842009-06-26 09:27:50 +01009158 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9159 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01009160 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9161 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9162 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009163 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01009164 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9165 { } /* end */
9166};
9167
Kailang Yange2757d52008-08-26 13:17:46 +02009168static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
9169 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9170 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9171 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
9172 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
9173 HDA_CODEC_VOLUME_MONO("Center Playback Volume",
9174 0x0d, 1, 0x0, HDA_OUTPUT),
9175 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
9176 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
9177 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
9178 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
9179 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009180 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9181 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9182 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9183 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9184 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009185 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009186 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9187 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009188 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009189 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009190 { } /* end */
9191};
9192
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009193static struct snd_kcontrol_new alc889A_mb31_mixer[] = {
9194 /* Output mixers */
9195 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
9196 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
9197 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
9198 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
9199 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00,
9200 HDA_OUTPUT),
9201 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT),
9202 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT),
9203 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT),
9204 /* Output switches */
9205 HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT),
9206 HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT),
9207 HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT),
9208 /* Boost mixers */
David Henningsson5f99f862011-01-04 15:24:24 +01009209 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT),
9210 HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT),
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009211 /* Input mixers */
9212 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
9213 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
9214 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9215 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9216 { } /* end */
9217};
9218
Guido Günther3e1647c2009-06-05 00:47:26 +02009219static struct snd_kcontrol_new alc883_vaiott_mixer[] = {
9220 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9221 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9222 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9223 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009224 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
Guido Günther3e1647c2009-06-05 00:47:26 +02009225 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
9226 { } /* end */
9227};
9228
Kailang Yange2757d52008-08-26 13:17:46 +02009229static struct hda_bind_ctls alc883_bind_cap_vol = {
9230 .ops = &snd_hda_bind_vol,
9231 .values = {
9232 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
9233 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
9234 0
9235 },
9236};
9237
9238static struct hda_bind_ctls alc883_bind_cap_switch = {
9239 .ops = &snd_hda_bind_sw,
9240 .values = {
9241 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
9242 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
9243 0
9244 },
9245};
9246
9247static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
9248 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9249 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9250 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9251 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9252 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9253 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009254 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009255 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009256 { } /* end */
9257};
9258
9259static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009260 HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
9261 HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
9262 {
9263 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9264 /* .name = "Capture Source", */
9265 .name = "Input Source",
9266 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01009267 .info = alc_mux_enum_info,
9268 .get = alc_mux_enum_get,
9269 .put = alc_mux_enum_put,
Kailang Yange2757d52008-08-26 13:17:46 +02009270 },
9271 { } /* end */
9272};
9273
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009274static struct snd_kcontrol_new alc883_chmode_mixer[] = {
9275 {
9276 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9277 .name = "Channel Mode",
9278 .info = alc_ch_mode_info,
9279 .get = alc_ch_mode_get,
9280 .put = alc_ch_mode_put,
9281 },
9282 { } /* end */
9283};
9284
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009285/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009286static void alc883_mitac_setup(struct hda_codec *codec)
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009287{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009288 struct alc_spec *spec = codec->spec;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009289
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009290 spec->autocfg.hp_pins[0] = 0x15;
9291 spec->autocfg.speaker_pins[0] = 0x14;
9292 spec->autocfg.speaker_pins[1] = 0x17;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009293}
9294
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009295static struct hda_verb alc883_mitac_verbs[] = {
9296 /* HP */
9297 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9298 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9299 /* Subwoofer */
9300 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
9301 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9302
9303 /* enable unsolicited event */
9304 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9305 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
9306
9307 { } /* end */
9308};
9309
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309310static struct hda_verb alc883_clevo_m540r_verbs[] = {
9311 /* HP */
9312 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9313 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9314 /* Int speaker */
9315 /*{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},*/
9316
9317 /* enable unsolicited event */
9318 /*
9319 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9320 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
9321 */
9322
9323 { } /* end */
9324};
9325
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009326static struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01009327 /* HP */
9328 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9329 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9330 /* Int speaker */
9331 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
9332 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9333
9334 /* enable unsolicited event */
9335 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009336 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01009337
9338 { } /* end */
9339};
9340
Jiang zhefb97dc62008-03-06 11:07:11 +01009341static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
9342 /* HP */
9343 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9344 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9345 /* Subwoofer */
9346 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
9347 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9348
9349 /* enable unsolicited event */
9350 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9351
9352 { } /* end */
9353};
9354
Sasha Alexandrc2592492009-06-16 14:52:54 -04009355static struct hda_verb alc883_targa_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02009356 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9357 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9358
9359 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9360 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02009361
David Heidelberger64a8be72009-06-08 16:15:18 +02009362/* Connect Line-Out side jack (SPDIF) to Side */
9363 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9364 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9365 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
9366/* Connect Mic jack to CLFE */
9367 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9368 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9369 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
9370/* Connect Line-in jack to Surround */
9371 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9372 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9373 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
9374/* Connect HP out jack to Front */
9375 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9376 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9377 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangccc656c2006-10-17 12:32:26 +02009378
9379 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangccc656c2006-10-17 12:32:26 +02009380
9381 { } /* end */
9382};
9383
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009384static struct hda_verb alc883_lenovo_101e_verbs[] = {
9385 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9386 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
9387 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
9388 { } /* end */
9389};
9390
Kailang Yang272a5272007-05-14 11:00:38 +02009391static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
9392 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9393 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9394 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9395 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9396 { } /* end */
9397};
9398
9399static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
9400 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9401 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9402 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9403 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
9404 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9405 { } /* end */
9406};
9407
Kailang Yang189609a2007-08-20 11:31:23 +02009408static struct hda_verb alc883_haier_w66_verbs[] = {
9409 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9410 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9411
9412 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9413
9414 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9415 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9416 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9417 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9418 { } /* end */
9419};
9420
Kailang Yange2757d52008-08-26 13:17:46 +02009421static struct hda_verb alc888_lenovo_sky_verbs[] = {
9422 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9423 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9424 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9425 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9426 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9427 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9428 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
9429 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9430 { } /* end */
9431};
9432
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009433static struct hda_verb alc888_6st_dell_verbs[] = {
9434 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9435 { }
9436};
9437
Guido Günther3e1647c2009-06-05 00:47:26 +02009438static struct hda_verb alc883_vaiott_verbs[] = {
9439 /* HP */
9440 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9441 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9442
9443 /* enable unsolicited event */
9444 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9445
9446 { } /* end */
9447};
9448
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009449static void alc888_3st_hp_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009450{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009451 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009452
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009453 spec->autocfg.hp_pins[0] = 0x1b;
9454 spec->autocfg.speaker_pins[0] = 0x14;
9455 spec->autocfg.speaker_pins[1] = 0x16;
9456 spec->autocfg.speaker_pins[2] = 0x18;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009457}
9458
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009459static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009460 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01009461 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
9462 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009463 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009464 { } /* end */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009465};
9466
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009467/*
9468 * 2ch mode
9469 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009470static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009471 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9472 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9473 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
9474 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009475 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009476};
9477
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009478/*
9479 * 4ch mode
9480 */
9481static struct hda_verb alc888_3st_hp_4ch_init[] = {
9482 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9483 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9484 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9485 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9486 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
9487 { } /* end */
9488};
9489
9490/*
9491 * 6ch mode
9492 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009493static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009494 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9495 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009496 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009497 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9498 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009499 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
9500 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009501};
9502
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009503static struct hda_channel_mode alc888_3st_hp_modes[3] = {
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009504 { 2, alc888_3st_hp_2ch_init },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009505 { 4, alc888_3st_hp_4ch_init },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009506 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009507};
9508
Kailang Yang272a5272007-05-14 11:00:38 +02009509/* toggle front-jack and RCA according to the hp-jack state */
9510static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
9511{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009512 unsigned int present = snd_hda_jack_detect(codec, 0x1b);
Kailang Yangea1fb292008-08-26 12:58:38 +02009513
Takashi Iwai47fd8302007-08-10 17:11:07 +02009514 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9515 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9516 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9517 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02009518}
9519
9520/* toggle RCA according to the front-jack state */
9521static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
9522{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009523 unsigned int present = snd_hda_jack_detect(codec, 0x14);
Kailang Yangea1fb292008-08-26 12:58:38 +02009524
Takashi Iwai47fd8302007-08-10 17:11:07 +02009525 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9526 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02009527}
Takashi Iwai47fd8302007-08-10 17:11:07 +02009528
Kailang Yang272a5272007-05-14 11:00:38 +02009529static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
9530 unsigned int res)
9531{
9532 if ((res >> 26) == ALC880_HP_EVENT)
9533 alc888_lenovo_ms7195_front_automute(codec);
9534 if ((res >> 26) == ALC880_FRONT_EVENT)
9535 alc888_lenovo_ms7195_rca_automute(codec);
9536}
9537
Kailang Yang272a5272007-05-14 11:00:38 +02009538/* toggle speaker-output according to the hp-jack state */
Takashi Iwaidc427172010-11-29 07:42:59 +01009539static void alc883_lenovo_nb0763_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +02009540{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009541 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009542
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009543 spec->autocfg.hp_pins[0] = 0x14;
9544 spec->autocfg.speaker_pins[0] = 0x15;
Kailang Yang272a5272007-05-14 11:00:38 +02009545}
9546
Kailang Yangccc656c2006-10-17 12:32:26 +02009547/* toggle speaker-output according to the hp-jack state */
Sasha Alexandrc2592492009-06-16 14:52:54 -04009548#define alc883_targa_init_hook alc882_targa_init_hook
9549#define alc883_targa_unsol_event alc882_targa_unsol_event
Jiang zhe368c7a92008-03-04 11:20:33 +01009550
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009551static void alc883_clevo_m720_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009552{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009553 struct alc_spec *spec = codec->spec;
9554
9555 spec->autocfg.hp_pins[0] = 0x15;
9556 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009557}
9558
9559static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
9560{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009561 alc_automute_amp(codec);
Anisse Astiereeb43382010-12-16 12:19:47 +01009562 alc88x_simple_mic_automute(codec);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009563}
9564
9565static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01009566 unsigned int res)
9567{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009568 switch (res >> 26) {
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009569 case ALC880_MIC_EVENT:
Anisse Astiereeb43382010-12-16 12:19:47 +01009570 alc88x_simple_mic_automute(codec);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009571 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009572 default:
9573 alc_automute_amp_unsol_event(codec, res);
9574 break;
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009575 }
Jiang zhe368c7a92008-03-04 11:20:33 +01009576}
9577
Jiang zhefb97dc62008-03-06 11:07:11 +01009578/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009579static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01009580{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009581 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01009582
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009583 spec->autocfg.hp_pins[0] = 0x14;
9584 spec->autocfg.speaker_pins[0] = 0x15;
Jiang zhefb97dc62008-03-06 11:07:11 +01009585}
9586
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009587static void alc883_haier_w66_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01009588{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009589 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01009590
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009591 spec->autocfg.hp_pins[0] = 0x1b;
9592 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang189609a2007-08-20 11:31:23 +02009593}
9594
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009595static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
9596{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009597 int bits = snd_hda_jack_detect(codec, 0x14) ? HDA_AMP_MUTE : 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009598
Takashi Iwai47fd8302007-08-10 17:11:07 +02009599 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9600 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009601}
9602
9603static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
9604{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009605 int bits = snd_hda_jack_detect(codec, 0x1b) ? HDA_AMP_MUTE : 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009606
Takashi Iwai47fd8302007-08-10 17:11:07 +02009607 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9608 HDA_AMP_MUTE, bits);
9609 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9610 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009611}
9612
9613static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
9614 unsigned int res)
9615{
9616 if ((res >> 26) == ALC880_HP_EVENT)
9617 alc883_lenovo_101e_all_automute(codec);
9618 if ((res >> 26) == ALC880_FRONT_EVENT)
9619 alc883_lenovo_101e_ispeaker_automute(codec);
9620}
9621
Takashi Iwai676a9b52007-08-16 15:23:35 +02009622/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009623static void alc883_acer_aspire_setup(struct hda_codec *codec)
Takashi Iwai676a9b52007-08-16 15:23:35 +02009624{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009625 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009626
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009627 spec->autocfg.hp_pins[0] = 0x14;
9628 spec->autocfg.speaker_pins[0] = 0x15;
9629 spec->autocfg.speaker_pins[1] = 0x16;
Takashi Iwai676a9b52007-08-16 15:23:35 +02009630}
9631
Kailang Yangd1a991a2007-08-15 16:21:59 +02009632static struct hda_verb alc883_acer_eapd_verbs[] = {
9633 /* HP Pin: output 0 (0x0c) */
9634 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9635 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9636 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9637 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02009638 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9639 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009640 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009641 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
9642 /* eanable EAPD on medion laptop */
9643 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
9644 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02009645 /* enable unsolicited event */
9646 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009647 { }
9648};
9649
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009650static void alc888_6st_dell_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009651{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009652 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009653
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009654 spec->autocfg.hp_pins[0] = 0x1b;
9655 spec->autocfg.speaker_pins[0] = 0x14;
9656 spec->autocfg.speaker_pins[1] = 0x15;
9657 spec->autocfg.speaker_pins[2] = 0x16;
9658 spec->autocfg.speaker_pins[3] = 0x17;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009659}
9660
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009661static void alc888_lenovo_sky_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009662{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009663 struct alc_spec *spec = codec->spec;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009664
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009665 spec->autocfg.hp_pins[0] = 0x1b;
9666 spec->autocfg.speaker_pins[0] = 0x14;
9667 spec->autocfg.speaker_pins[1] = 0x15;
9668 spec->autocfg.speaker_pins[2] = 0x16;
9669 spec->autocfg.speaker_pins[3] = 0x17;
9670 spec->autocfg.speaker_pins[4] = 0x1a;
Kailang Yange2757d52008-08-26 13:17:46 +02009671}
9672
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009673static void alc883_vaiott_setup(struct hda_codec *codec)
Guido Günther3e1647c2009-06-05 00:47:26 +02009674{
9675 struct alc_spec *spec = codec->spec;
9676
9677 spec->autocfg.hp_pins[0] = 0x15;
9678 spec->autocfg.speaker_pins[0] = 0x14;
9679 spec->autocfg.speaker_pins[1] = 0x17;
Guido Günther3e1647c2009-06-05 00:47:26 +02009680}
9681
Kailang Yange2757d52008-08-26 13:17:46 +02009682static struct hda_verb alc888_asus_m90v_verbs[] = {
9683 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9684 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9685 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9686 /* enable unsolicited event */
9687 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9688 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
9689 { } /* end */
9690};
9691
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009692static void alc883_mode2_setup(struct hda_codec *codec)
Kailang Yange2757d52008-08-26 13:17:46 +02009693{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009694 struct alc_spec *spec = codec->spec;
Kailang Yange2757d52008-08-26 13:17:46 +02009695
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009696 spec->autocfg.hp_pins[0] = 0x1b;
9697 spec->autocfg.speaker_pins[0] = 0x14;
9698 spec->autocfg.speaker_pins[1] = 0x15;
9699 spec->autocfg.speaker_pins[2] = 0x16;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009700 spec->ext_mic.pin = 0x18;
9701 spec->int_mic.pin = 0x19;
9702 spec->ext_mic.mux_idx = 0;
9703 spec->int_mic.mux_idx = 1;
9704 spec->auto_mic = 1;
Kailang Yange2757d52008-08-26 13:17:46 +02009705}
9706
9707static struct hda_verb alc888_asus_eee1601_verbs[] = {
9708 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9709 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9710 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9711 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9712 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9713 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
9714 {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
9715 /* enable unsolicited event */
9716 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9717 { } /* end */
9718};
9719
Kailang Yange2757d52008-08-26 13:17:46 +02009720static void alc883_eee1601_inithook(struct hda_codec *codec)
9721{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009722 struct alc_spec *spec = codec->spec;
9723
9724 spec->autocfg.hp_pins[0] = 0x14;
9725 spec->autocfg.speaker_pins[0] = 0x1b;
9726 alc_automute_pin(codec);
Kailang Yange2757d52008-08-26 13:17:46 +02009727}
9728
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009729static struct hda_verb alc889A_mb31_verbs[] = {
9730 /* Init rear pin (used as headphone output) */
9731 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */
9732 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */
9733 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9734 /* Init line pin (used as output in 4ch and 6ch mode) */
9735 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Connect to CLFE */
9736 /* Init line 2 pin (used as headphone out by default) */
9737 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Use as input */
9738 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */
9739 { } /* end */
9740};
9741
9742/* Mute speakers according to the headphone jack state */
9743static void alc889A_mb31_automute(struct hda_codec *codec)
9744{
9745 unsigned int present;
9746
9747 /* Mute only in 2ch or 4ch mode */
9748 if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0)
9749 == 0x00) {
Wu Fengguang864f92b2009-11-18 12:38:02 +08009750 present = snd_hda_jack_detect(codec, 0x15);
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009751 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9752 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9753 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
9754 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9755 }
9756}
9757
9758static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
9759{
9760 if ((res >> 26) == ALC880_HP_EVENT)
9761 alc889A_mb31_automute(codec);
9762}
9763
Takashi Iwai49535502009-06-30 15:28:30 +02009764
Takashi Iwaicb53c622007-08-10 17:21:45 +02009765#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwai49535502009-06-30 15:28:30 +02009766#define alc882_loopbacks alc880_loopbacks
Takashi Iwaicb53c622007-08-10 17:21:45 +02009767#endif
9768
Sasha Alexandrdef319f2009-06-16 16:00:15 -04009769/* pcm configuration: identical with ALC880 */
Takashi Iwai49535502009-06-30 15:28:30 +02009770#define alc882_pcm_analog_playback alc880_pcm_analog_playback
9771#define alc882_pcm_analog_capture alc880_pcm_analog_capture
9772#define alc882_pcm_digital_playback alc880_pcm_digital_playback
9773#define alc882_pcm_digital_capture alc880_pcm_digital_capture
9774
9775static hda_nid_t alc883_slave_dig_outs[] = {
9776 ALC1200_DIGOUT_NID, 0,
9777};
9778
9779static hda_nid_t alc1200_slave_dig_outs[] = {
9780 ALC883_DIGOUT_NID, 0,
9781};
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009782
9783/*
9784 * configuration and preset
9785 */
Takashi Iwaiea734962011-01-17 11:29:34 +01009786static const char * const alc882_models[ALC882_MODEL_LAST] = {
Takashi Iwai49535502009-06-30 15:28:30 +02009787 [ALC882_3ST_DIG] = "3stack-dig",
9788 [ALC882_6ST_DIG] = "6stack-dig",
9789 [ALC882_ARIMA] = "arima",
9790 [ALC882_W2JC] = "w2jc",
9791 [ALC882_TARGA] = "targa",
9792 [ALC882_ASUS_A7J] = "asus-a7j",
9793 [ALC882_ASUS_A7M] = "asus-a7m",
9794 [ALC885_MACPRO] = "macpro",
9795 [ALC885_MB5] = "mb5",
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009796 [ALC885_MACMINI3] = "macmini3",
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08009797 [ALC885_MBA21] = "mba21",
Takashi Iwai49535502009-06-30 15:28:30 +02009798 [ALC885_MBP3] = "mbp3",
9799 [ALC885_IMAC24] = "imac24",
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009800 [ALC885_IMAC91] = "imac91",
Takashi Iwai49535502009-06-30 15:28:30 +02009801 [ALC883_3ST_2ch_DIG] = "3stack-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009802 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
9803 [ALC883_3ST_6ch] = "3stack-6ch",
Takashi Iwai49535502009-06-30 15:28:30 +02009804 [ALC883_6ST_DIG] = "alc883-6stack-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009805 [ALC883_TARGA_DIG] = "targa-dig",
9806 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
David Heidelberger64a8be72009-06-08 16:15:18 +02009807 [ALC883_TARGA_8ch_DIG] = "targa-8ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009808 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02009809 [ALC883_ACER_ASPIRE] = "acer-aspire",
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009810 [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g",
Takashi Iwaib1a91462009-06-21 10:56:44 +02009811 [ALC888_ACER_ASPIRE_6530G] = "acer-aspire-6530g",
Hector Martin3b315d72009-06-02 10:54:19 +02009812 [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g",
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009813 [ALC888_ACER_ASPIRE_7730G] = "acer-aspire-7730g",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009814 [ALC883_MEDION] = "medion",
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009815 [ALC883_MEDION_WIM2160] = "medion-wim2160",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009816 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009817 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02009818 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
9819 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yange2757d52008-08-26 13:17:46 +02009820 [ALC888_LENOVO_SKY] = "lenovo-sky",
Kailang Yang189609a2007-08-20 11:31:23 +02009821 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009822 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009823 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009824 [ALC883_MITAC] = "mitac",
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309825 [ALC883_CLEVO_M540R] = "clevo-m540r",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009826 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +01009827 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009828 [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
Jiang zhe17bba1b2008-06-04 12:11:07 +02009829 [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009830 [ALC889A_INTEL] = "intel-alc889a",
9831 [ALC889_INTEL] = "intel-x58",
Wu Fengguang3ab90932008-11-17 09:51:09 +01009832 [ALC1200_ASUS_P5Q] = "asus-p5q",
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009833 [ALC889A_MB31] = "mb31",
Guido Günther3e1647c2009-06-05 00:47:26 +02009834 [ALC883_SONY_VAIO_TT] = "sony-vaio-tt",
Takashi Iwai49535502009-06-30 15:28:30 +02009835 [ALC882_AUTO] = "auto",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009836};
9837
Takashi Iwai49535502009-06-30 15:28:30 +02009838static struct snd_pci_quirk alc882_cfg_tbl[] = {
9839 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
9840
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009841 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
Takashi Iwai69e50282008-11-03 10:07:43 +01009842 SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
Takashi Iwai9b6682f2009-03-23 22:50:52 +01009843 SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009844 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
9845 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
Jaroslav Kysela0b18cb12008-07-28 17:07:07 +02009846 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009847 SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
9848 ALC888_ACER_ASPIRE_4930G),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01009849 SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
Takashi Iwai83dd7402009-11-24 08:57:53 +01009850 ALC888_ACER_ASPIRE_4930G),
Hector Martin3b315d72009-06-02 10:54:19 +02009851 SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
9852 ALC888_ACER_ASPIRE_8930G),
Takashi Iwaie46b0c82009-06-13 10:16:43 +02009853 SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
9854 ALC888_ACER_ASPIRE_8930G),
Takashi Iwai49535502009-06-30 15:28:30 +02009855 SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO),
9856 SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01009857 SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
Takashi Iwaidde65352009-06-25 08:25:35 +02009858 ALC888_ACER_ASPIRE_6530G),
Juan Jesus Garcia de Soriacc374c42009-02-23 08:11:59 +01009859 SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
Tony Vroond2fd4b02009-06-21 00:40:10 +01009860 ALC888_ACER_ASPIRE_6530G),
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009861 SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
9862 ALC888_ACER_ASPIRE_7730G),
Takashi Iwai22b530e2009-05-13 11:32:52 +02009863 /* default Acer -- disabled as it causes more problems.
9864 * model=auto should work fine now
9865 */
9866 /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */
Takashi Iwai49535502009-06-30 15:28:30 +02009867
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009868 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Takashi Iwai49535502009-06-30 15:28:30 +02009869
Tobin Davisfebe3372007-06-12 11:27:46 +02009870 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009871 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
9872 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +01009873 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Chris Bagwell06bf3e12009-01-01 10:32:08 +01009874 SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
Herton Ronaldo Krzesinski7ec30f02009-03-04 14:22:52 -03009875 SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
Takashi Iwai49535502009-06-30 15:28:30 +02009876
9877 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
9878 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
9879 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Kailang Yanga01c30c2008-10-15 11:14:58 +02009880 SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
Takashi Iwai49535502009-06-30 15:28:30 +02009881 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
9882 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
9883 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009884 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Mackenzie Morgan44a678d2009-02-10 17:13:43 +01009885 SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
Wu Fengguang3ab90932008-11-17 09:51:09 +01009886 SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
Kailang Yange2757d52008-08-26 13:17:46 +02009887 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
Takashi Iwai49535502009-06-30 15:28:30 +02009888
9889 SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
Travis Place97ec7102008-05-23 18:31:46 +02009890 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009891 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009892 SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009893 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
9894 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
Kailang Yange2757d52008-08-26 13:17:46 +02009895 SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009896 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Takashi Iwai49535502009-06-30 15:28:30 +02009897 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
9898
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009899 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
9900 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
9901 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009902 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
Takashi Iwai2fef62c2009-12-18 08:48:42 +01009903 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC882_AUTO),
Takashi Iwai49535502009-06-30 15:28:30 +02009904 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009905 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01009906 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009907 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
9908 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
9909 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
9910 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
9911 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
9912 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009913 SND_PCI_QUIRK(0x1462, 0x42cd, "MSI", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009914 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
9915 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
9916 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Anisse Astierb43f6e52010-03-10 19:17:46 +01009917 SND_PCI_QUIRK(0x1462, 0x4570, "MSI Wind Top AE2220", ALC883_TARGA_DIG),
David Heidelberger64a8be72009-06-08 16:15:18 +02009918 SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009919 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
9920 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02009921 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Takashi Iwaiee095432008-11-25 15:03:38 +01009922 SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +01009923 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01009924 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02009925 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Sasha Alexandrdf01b8a2009-06-16 14:46:17 -04009926 SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG),
Anisse Astierb43f6e52010-03-10 19:17:46 +01009927 SND_PCI_QUIRK(0x1462, 0x7437, "MSI NetOn AP1900", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009928 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009929 SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009930
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009931 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Joerg Schirottked1501ea2010-04-15 08:37:41 +02009932 SND_PCI_QUIRK(0x1558, 0x0571, "Clevo laptop M570U", ALC883_3ST_6ch_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009933 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
9934 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309935 SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R),
Takashi Iwaidea0a502009-02-09 17:14:52 +01009936 SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04009937 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwai49535502009-06-30 15:28:30 +02009938 /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009939 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009940 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
Takashi Iwaif67d8172009-02-04 23:30:19 +01009941 ALC883_FUJITSU_PI2515),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009942 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009943 ALC888_FUJITSU_XA3530),
Kailang Yang272a5272007-05-14 11:00:38 +02009944 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02009945 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009946 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
9947 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yange2757d52008-08-26 13:17:46 +02009948 SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
Takashi Iwai959973b2008-11-05 11:30:56 +01009949 SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01009950 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02009951 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Takashi Iwai49535502009-06-30 15:28:30 +02009952
Jiang zhe17bba1b2008-06-04 12:11:07 +02009953 SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
9954 SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009955 SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009956 SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL),
9957 SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL),
9958 SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL),
Daniel T Chen572c0e32010-03-14 23:44:03 -04009959 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC882_6ST_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009960
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009961 {}
9962};
9963
Takashi Iwai49535502009-06-30 15:28:30 +02009964/* codec SSID table for Intel Mac */
9965static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
9966 SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3),
9967 SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3),
9968 SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3),
9969 SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO),
9970 SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24),
9971 SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24),
9972 SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3),
Daniel T Chen26fd74f2010-05-30 09:55:23 -04009973 SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31),
Justin P. Mattockab669962010-06-06 16:09:53 -07009974 SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_ASUS_A7M),
Justin P. Mattockf53dae22010-06-06 16:09:51 -07009975 SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC885_MBP3),
Justin P. Mattock6e129702010-06-06 16:09:49 -07009976 SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC885_MBA21),
Takashi Iwai49535502009-06-30 15:28:30 +02009977 SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
9978 SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
9979 SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009980 SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91),
Takashi Iwai49535502009-06-30 15:28:30 +02009981 SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5),
Luke Yelavich3bfea982010-06-22 11:04:19 +10009982 SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -05009983 /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2,
9984 * so apparently no perfect solution yet
Takashi Iwai49535502009-06-30 15:28:30 +02009985 */
9986 SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -05009987 SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5),
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009988 SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC885_MACMINI3),
Takashi Iwai49535502009-06-30 15:28:30 +02009989 {} /* terminator */
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08009990};
9991
Takashi Iwai49535502009-06-30 15:28:30 +02009992static struct alc_config_preset alc882_presets[] = {
9993 [ALC882_3ST_DIG] = {
9994 .mixers = { alc882_base_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009995 .init_verbs = { alc882_base_init_verbs,
9996 alc882_adc1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +02009997 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9998 .dac_nids = alc882_dac_nids,
9999 .dig_out_nid = ALC882_DIGOUT_NID,
10000 .dig_in_nid = ALC882_DIGIN_NID,
10001 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
10002 .channel_mode = alc882_ch_modes,
10003 .need_dac_fix = 1,
10004 .input_mux = &alc882_capture_source,
10005 },
10006 [ALC882_6ST_DIG] = {
10007 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010008 .init_verbs = { alc882_base_init_verbs,
10009 alc882_adc1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +020010010 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10011 .dac_nids = alc882_dac_nids,
10012 .dig_out_nid = ALC882_DIGOUT_NID,
10013 .dig_in_nid = ALC882_DIGIN_NID,
10014 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
10015 .channel_mode = alc882_sixstack_modes,
10016 .input_mux = &alc882_capture_source,
10017 },
10018 [ALC882_ARIMA] = {
10019 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010020 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10021 alc882_eapd_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +020010022 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10023 .dac_nids = alc882_dac_nids,
10024 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
10025 .channel_mode = alc882_sixstack_modes,
10026 .input_mux = &alc882_capture_source,
10027 },
10028 [ALC882_W2JC] = {
10029 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010030 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10031 alc882_eapd_verbs, alc880_gpio1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +020010032 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10033 .dac_nids = alc882_dac_nids,
10034 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
10035 .channel_mode = alc880_threestack_modes,
10036 .need_dac_fix = 1,
10037 .input_mux = &alc882_capture_source,
10038 .dig_out_nid = ALC882_DIGOUT_NID,
10039 },
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -080010040 [ALC885_MBA21] = {
10041 .mixers = { alc885_mba21_mixer },
10042 .init_verbs = { alc885_mba21_init_verbs, alc880_gpio1_init_verbs },
10043 .num_dacs = 2,
10044 .dac_nids = alc882_dac_nids,
10045 .channel_mode = alc885_mba21_ch_modes,
10046 .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
10047 .input_mux = &alc882_capture_source,
10048 .unsol_event = alc_automute_amp_unsol_event,
10049 .setup = alc885_mba21_setup,
10050 .init_hook = alc_automute_amp,
10051 },
Takashi Iwai49535502009-06-30 15:28:30 +020010052 [ALC885_MBP3] = {
10053 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
10054 .init_verbs = { alc885_mbp3_init_verbs,
10055 alc880_gpio1_init_verbs },
Takashi Iwaibe0ae922009-08-31 08:27:10 +020010056 .num_dacs = 2,
Takashi Iwai49535502009-06-30 15:28:30 +020010057 .dac_nids = alc882_dac_nids,
Takashi Iwaibe0ae922009-08-31 08:27:10 +020010058 .hp_nid = 0x04,
10059 .channel_mode = alc885_mbp_4ch_modes,
10060 .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes),
Takashi Iwai49535502009-06-30 15:28:30 +020010061 .input_mux = &alc882_capture_source,
10062 .dig_out_nid = ALC882_DIGOUT_NID,
10063 .dig_in_nid = ALC882_DIGIN_NID,
10064 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010065 .setup = alc885_mbp3_setup,
10066 .init_hook = alc_automute_amp,
Takashi Iwai49535502009-06-30 15:28:30 +020010067 },
10068 [ALC885_MB5] = {
10069 .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
10070 .init_verbs = { alc885_mb5_init_verbs,
10071 alc880_gpio1_init_verbs },
10072 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10073 .dac_nids = alc882_dac_nids,
10074 .channel_mode = alc885_mb5_6ch_modes,
10075 .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
10076 .input_mux = &mb5_capture_source,
10077 .dig_out_nid = ALC882_DIGOUT_NID,
10078 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +010010079 .unsol_event = alc_automute_amp_unsol_event,
10080 .setup = alc885_mb5_setup,
10081 .init_hook = alc_automute_amp,
Takashi Iwai49535502009-06-30 15:28:30 +020010082 },
Luke Yelaviche458b1f2010-02-12 16:28:29 +110010083 [ALC885_MACMINI3] = {
10084 .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer },
10085 .init_verbs = { alc885_macmini3_init_verbs,
10086 alc880_gpio1_init_verbs },
10087 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10088 .dac_nids = alc882_dac_nids,
10089 .channel_mode = alc885_macmini3_6ch_modes,
10090 .num_channel_mode = ARRAY_SIZE(alc885_macmini3_6ch_modes),
10091 .input_mux = &macmini3_capture_source,
10092 .dig_out_nid = ALC882_DIGOUT_NID,
10093 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +010010094 .unsol_event = alc_automute_amp_unsol_event,
10095 .setup = alc885_macmini3_setup,
10096 .init_hook = alc_automute_amp,
Luke Yelaviche458b1f2010-02-12 16:28:29 +110010097 },
Takashi Iwai49535502009-06-30 15:28:30 +020010098 [ALC885_MACPRO] = {
10099 .mixers = { alc882_macpro_mixer },
10100 .init_verbs = { alc882_macpro_init_verbs },
10101 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10102 .dac_nids = alc882_dac_nids,
10103 .dig_out_nid = ALC882_DIGOUT_NID,
10104 .dig_in_nid = ALC882_DIGIN_NID,
10105 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
10106 .channel_mode = alc882_ch_modes,
10107 .input_mux = &alc882_capture_source,
10108 .init_hook = alc885_macpro_init_hook,
10109 },
10110 [ALC885_IMAC24] = {
10111 .mixers = { alc885_imac24_mixer },
10112 .init_verbs = { alc885_imac24_init_verbs },
10113 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10114 .dac_nids = alc882_dac_nids,
10115 .dig_out_nid = ALC882_DIGOUT_NID,
10116 .dig_in_nid = ALC882_DIGIN_NID,
10117 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
10118 .channel_mode = alc882_ch_modes,
10119 .input_mux = &alc882_capture_source,
10120 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010121 .setup = alc885_imac24_setup,
Takashi Iwai49535502009-06-30 15:28:30 +020010122 .init_hook = alc885_imac24_init_hook,
10123 },
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010124 [ALC885_IMAC91] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -070010125 .mixers = {alc885_imac91_mixer},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010126 .init_verbs = { alc885_imac91_init_verbs,
10127 alc880_gpio1_init_verbs },
10128 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10129 .dac_nids = alc882_dac_nids,
Justin P. Mattockb7cccc52010-05-23 10:55:00 -070010130 .channel_mode = alc885_mba21_ch_modes,
10131 .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
10132 .input_mux = &alc889A_imac91_capture_source,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010133 .dig_out_nid = ALC882_DIGOUT_NID,
10134 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +010010135 .unsol_event = alc_automute_amp_unsol_event,
10136 .setup = alc885_imac91_setup,
10137 .init_hook = alc_automute_amp,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010138 },
Takashi Iwai49535502009-06-30 15:28:30 +020010139 [ALC882_TARGA] = {
10140 .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010141 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
Takashi Iwai31909b82009-07-10 12:33:48 +020010142 alc880_gpio3_init_verbs, alc882_targa_verbs},
Takashi Iwai49535502009-06-30 15:28:30 +020010143 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10144 .dac_nids = alc882_dac_nids,
10145 .dig_out_nid = ALC882_DIGOUT_NID,
10146 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
10147 .adc_nids = alc882_adc_nids,
10148 .capsrc_nids = alc882_capsrc_nids,
10149 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
10150 .channel_mode = alc882_3ST_6ch_modes,
10151 .need_dac_fix = 1,
10152 .input_mux = &alc882_capture_source,
10153 .unsol_event = alc882_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010154 .setup = alc882_targa_setup,
10155 .init_hook = alc882_targa_automute,
Takashi Iwai49535502009-06-30 15:28:30 +020010156 },
10157 [ALC882_ASUS_A7J] = {
10158 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010159 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10160 alc882_asus_a7j_verbs},
Takashi Iwai49535502009-06-30 15:28:30 +020010161 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10162 .dac_nids = alc882_dac_nids,
10163 .dig_out_nid = ALC882_DIGOUT_NID,
10164 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
10165 .adc_nids = alc882_adc_nids,
10166 .capsrc_nids = alc882_capsrc_nids,
10167 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
10168 .channel_mode = alc882_3ST_6ch_modes,
10169 .need_dac_fix = 1,
10170 .input_mux = &alc882_capture_source,
10171 },
10172 [ALC882_ASUS_A7M] = {
10173 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010174 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10175 alc882_eapd_verbs, alc880_gpio1_init_verbs,
Takashi Iwai49535502009-06-30 15:28:30 +020010176 alc882_asus_a7m_verbs },
10177 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10178 .dac_nids = alc882_dac_nids,
10179 .dig_out_nid = ALC882_DIGOUT_NID,
10180 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
10181 .channel_mode = alc880_threestack_modes,
10182 .need_dac_fix = 1,
10183 .input_mux = &alc882_capture_source,
10184 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010185 [ALC883_3ST_2ch_DIG] = {
10186 .mixers = { alc883_3ST_2ch_mixer },
10187 .init_verbs = { alc883_init_verbs },
10188 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10189 .dac_nids = alc883_dac_nids,
10190 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010191 .dig_in_nid = ALC883_DIGIN_NID,
10192 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10193 .channel_mode = alc883_3ST_2ch_modes,
10194 .input_mux = &alc883_capture_source,
10195 },
10196 [ALC883_3ST_6ch_DIG] = {
10197 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10198 .init_verbs = { alc883_init_verbs },
10199 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10200 .dac_nids = alc883_dac_nids,
10201 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010202 .dig_in_nid = ALC883_DIGIN_NID,
10203 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10204 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020010205 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010206 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010207 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010208 [ALC883_3ST_6ch] = {
10209 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10210 .init_verbs = { alc883_init_verbs },
10211 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10212 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010213 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10214 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020010215 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010216 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010217 },
Jiang zhe17bba1b2008-06-04 12:11:07 +020010218 [ALC883_3ST_6ch_INTEL] = {
10219 .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
10220 .init_verbs = { alc883_init_verbs },
10221 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10222 .dac_nids = alc883_dac_nids,
10223 .dig_out_nid = ALC883_DIGOUT_NID,
10224 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangf3cd3f52009-04-02 19:44:18 +080010225 .slave_dig_outs = alc883_slave_dig_outs,
Jiang zhe17bba1b2008-06-04 12:11:07 +020010226 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
10227 .channel_mode = alc883_3ST_6ch_intel_modes,
10228 .need_dac_fix = 1,
10229 .input_mux = &alc883_3stack_6ch_intel,
10230 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010231 [ALC889A_INTEL] = {
10232 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020010233 .init_verbs = { alc885_init_verbs, alc885_init_input_verbs,
10234 alc_hp15_unsol_verbs },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010235 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10236 .dac_nids = alc883_dac_nids,
10237 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10238 .adc_nids = alc889_adc_nids,
10239 .dig_out_nid = ALC883_DIGOUT_NID,
10240 .dig_in_nid = ALC883_DIGIN_NID,
10241 .slave_dig_outs = alc883_slave_dig_outs,
10242 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
10243 .channel_mode = alc889_8ch_intel_modes,
10244 .capsrc_nids = alc889_capsrc_nids,
10245 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010246 .setup = alc889_automute_setup,
10247 .init_hook = alc_automute_amp,
Wu Fengguang6732bd02009-07-30 09:19:14 +020010248 .unsol_event = alc_automute_amp_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010249 .need_dac_fix = 1,
10250 },
10251 [ALC889_INTEL] = {
10252 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
10253 .init_verbs = { alc885_init_verbs, alc889_init_input_verbs,
Wu Fengguang6732bd02009-07-30 09:19:14 +020010254 alc889_eapd_verbs, alc_hp15_unsol_verbs},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010255 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10256 .dac_nids = alc883_dac_nids,
10257 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10258 .adc_nids = alc889_adc_nids,
10259 .dig_out_nid = ALC883_DIGOUT_NID,
10260 .dig_in_nid = ALC883_DIGIN_NID,
10261 .slave_dig_outs = alc883_slave_dig_outs,
10262 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
10263 .channel_mode = alc889_8ch_intel_modes,
10264 .capsrc_nids = alc889_capsrc_nids,
10265 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010266 .setup = alc889_automute_setup,
Wu Fengguang6732bd02009-07-30 09:19:14 +020010267 .init_hook = alc889_intel_init_hook,
10268 .unsol_event = alc_automute_amp_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010269 .need_dac_fix = 1,
10270 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010271 [ALC883_6ST_DIG] = {
10272 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
10273 .init_verbs = { alc883_init_verbs },
10274 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10275 .dac_nids = alc883_dac_nids,
10276 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010277 .dig_in_nid = ALC883_DIGIN_NID,
10278 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10279 .channel_mode = alc883_sixstack_modes,
10280 .input_mux = &alc883_capture_source,
10281 },
Kailang Yangccc656c2006-10-17 12:32:26 +020010282 [ALC883_TARGA_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010283 .mixers = { alc883_targa_mixer, alc883_chmode_mixer },
David Heidelberger005b1072009-07-09 18:45:46 +020010284 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
10285 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020010286 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10287 .dac_nids = alc883_dac_nids,
10288 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +020010289 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10290 .channel_mode = alc883_3ST_6ch_modes,
10291 .need_dac_fix = 1,
10292 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010293 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010294 .setup = alc882_targa_setup,
10295 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010296 },
10297 [ALC883_TARGA_2ch_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010298 .mixers = { alc883_targa_2ch_mixer},
David Heidelberger005b1072009-07-09 18:45:46 +020010299 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
10300 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020010301 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10302 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010303 .adc_nids = alc883_adc_nids_alt,
10304 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010305 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangccc656c2006-10-17 12:32:26 +020010306 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +020010307 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10308 .channel_mode = alc883_3ST_2ch_modes,
10309 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010310 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010311 .setup = alc882_targa_setup,
10312 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010313 },
David Heidelberger64a8be72009-06-08 16:15:18 +020010314 [ALC883_TARGA_8ch_DIG] = {
Takashi Iwaib99dba32009-09-17 18:23:00 +020010315 .mixers = { alc883_targa_mixer, alc883_targa_8ch_mixer,
10316 alc883_chmode_mixer },
David Heidelberger64a8be72009-06-08 16:15:18 +020010317 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010318 alc883_targa_verbs },
David Heidelberger64a8be72009-06-08 16:15:18 +020010319 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10320 .dac_nids = alc883_dac_nids,
10321 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10322 .adc_nids = alc883_adc_nids_rev,
10323 .capsrc_nids = alc883_capsrc_nids_rev,
10324 .dig_out_nid = ALC883_DIGOUT_NID,
10325 .dig_in_nid = ALC883_DIGIN_NID,
10326 .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes),
10327 .channel_mode = alc883_4ST_8ch_modes,
10328 .need_dac_fix = 1,
10329 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010330 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010331 .setup = alc882_targa_setup,
10332 .init_hook = alc882_targa_automute,
David Heidelberger64a8be72009-06-08 16:15:18 +020010333 },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +020010334 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010335 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +020010336 /* On TravelMate laptops, GPIO 0 enables the internal speaker
10337 * and the headphone jack. Turn this on and rely on the
10338 * standard mute methods whenever the user wants to turn
10339 * these outputs off.
10340 */
10341 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
10342 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10343 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +020010344 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10345 .channel_mode = alc883_3ST_2ch_modes,
10346 .input_mux = &alc883_capture_source,
10347 },
Tobin Davis2880a862007-08-07 11:50:26 +020010348 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010349 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +020010350 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +020010351 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10352 .dac_nids = alc883_dac_nids,
10353 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +020010354 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10355 .channel_mode = alc883_3ST_2ch_modes,
10356 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010357 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010358 .setup = alc883_acer_aspire_setup,
10359 .init_hook = alc_automute_amp,
Kailang Yangd1a991a2007-08-15 16:21:59 +020010360 },
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010361 [ALC888_ACER_ASPIRE_4930G] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010362 .mixers = { alc888_base_mixer,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010363 alc883_chmode_mixer },
10364 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10365 alc888_acer_aspire_4930g_verbs },
10366 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10367 .dac_nids = alc883_dac_nids,
10368 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10369 .adc_nids = alc883_adc_nids_rev,
10370 .capsrc_nids = alc883_capsrc_nids_rev,
10371 .dig_out_nid = ALC883_DIGOUT_NID,
10372 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10373 .channel_mode = alc883_3ST_6ch_modes,
10374 .need_dac_fix = 1,
Łukasz Wojniłowicz973b8cb2010-01-24 14:12:37 +010010375 .const_channel_count = 6,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010376 .num_mux_defs =
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010377 ARRAY_SIZE(alc888_2_capture_sources),
10378 .input_mux = alc888_2_capture_sources,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010379 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010380 .setup = alc888_acer_aspire_4930g_setup,
10381 .init_hook = alc_automute_amp,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010382 },
Tony Vroond2fd4b02009-06-21 00:40:10 +010010383 [ALC888_ACER_ASPIRE_6530G] = {
10384 .mixers = { alc888_acer_aspire_6530_mixer },
10385 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10386 alc888_acer_aspire_6530g_verbs },
10387 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10388 .dac_nids = alc883_dac_nids,
10389 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10390 .adc_nids = alc883_adc_nids_rev,
10391 .capsrc_nids = alc883_capsrc_nids_rev,
10392 .dig_out_nid = ALC883_DIGOUT_NID,
10393 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10394 .channel_mode = alc883_3ST_2ch_modes,
10395 .num_mux_defs =
10396 ARRAY_SIZE(alc888_2_capture_sources),
10397 .input_mux = alc888_acer_aspire_6530_sources,
10398 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010399 .setup = alc888_acer_aspire_6530g_setup,
10400 .init_hook = alc_automute_amp,
Tony Vroond2fd4b02009-06-21 00:40:10 +010010401 },
Hector Martin3b315d72009-06-02 10:54:19 +020010402 [ALC888_ACER_ASPIRE_8930G] = {
Hector Martin556eea92009-12-20 22:51:23 +010010403 .mixers = { alc889_acer_aspire_8930g_mixer,
Hector Martin3b315d72009-06-02 10:54:19 +020010404 alc883_chmode_mixer },
10405 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
Hector Martin0f86a222009-12-20 22:51:18 +010010406 alc889_acer_aspire_8930g_verbs,
10407 alc889_eapd_verbs},
Hector Martin3b315d72009-06-02 10:54:19 +020010408 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10409 .dac_nids = alc883_dac_nids,
Hector Martin018df412009-06-04 00:13:40 +020010410 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10411 .adc_nids = alc889_adc_nids,
10412 .capsrc_nids = alc889_capsrc_nids,
Hector Martin3b315d72009-06-02 10:54:19 +020010413 .dig_out_nid = ALC883_DIGOUT_NID,
10414 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10415 .channel_mode = alc883_3ST_6ch_modes,
10416 .need_dac_fix = 1,
10417 .const_channel_count = 6,
10418 .num_mux_defs =
Hector Martin018df412009-06-04 00:13:40 +020010419 ARRAY_SIZE(alc889_capture_sources),
10420 .input_mux = alc889_capture_sources,
Hector Martin3b315d72009-06-02 10:54:19 +020010421 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010422 .setup = alc889_acer_aspire_8930g_setup,
10423 .init_hook = alc_automute_amp,
Hector Martinf5de24b2009-12-20 22:51:31 +010010424#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050010425 .power_hook = alc_power_eapd,
Hector Martinf5de24b2009-12-20 22:51:31 +010010426#endif
Hector Martin3b315d72009-06-02 10:54:19 +020010427 },
Denis Kuplyakovfc86f952009-08-25 18:15:59 +020010428 [ALC888_ACER_ASPIRE_7730G] = {
10429 .mixers = { alc883_3ST_6ch_mixer,
10430 alc883_chmode_mixer },
10431 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10432 alc888_acer_aspire_7730G_verbs },
10433 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10434 .dac_nids = alc883_dac_nids,
10435 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10436 .adc_nids = alc883_adc_nids_rev,
10437 .capsrc_nids = alc883_capsrc_nids_rev,
10438 .dig_out_nid = ALC883_DIGOUT_NID,
10439 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10440 .channel_mode = alc883_3ST_6ch_modes,
10441 .need_dac_fix = 1,
10442 .const_channel_count = 6,
10443 .input_mux = &alc883_capture_source,
10444 .unsol_event = alc_automute_amp_unsol_event,
Denis Kuplyakovd9477202010-11-24 06:01:09 +010010445 .setup = alc888_acer_aspire_7730g_setup,
Denis Kuplyakovfc86f952009-08-25 18:15:59 +020010446 .init_hook = alc_automute_amp,
10447 },
Tobin Davisc07584c2006-10-13 12:32:16 +020010448 [ALC883_MEDION] = {
10449 .mixers = { alc883_fivestack_mixer,
10450 alc883_chmode_mixer },
10451 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010452 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +020010453 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10454 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010455 .adc_nids = alc883_adc_nids_alt,
10456 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010457 .capsrc_nids = alc883_capsrc_nids,
Tobin Davisc07584c2006-10-13 12:32:16 +020010458 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10459 .channel_mode = alc883_sixstack_modes,
10460 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010461 },
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +020010462 [ALC883_MEDION_WIM2160] = {
10463 .mixers = { alc883_medion_wim2160_mixer },
10464 .init_verbs = { alc883_init_verbs, alc883_medion_wim2160_verbs },
10465 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10466 .dac_nids = alc883_dac_nids,
10467 .dig_out_nid = ALC883_DIGOUT_NID,
10468 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
10469 .adc_nids = alc883_adc_nids,
10470 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10471 .channel_mode = alc883_3ST_2ch_modes,
10472 .input_mux = &alc883_capture_source,
10473 .unsol_event = alc_automute_amp_unsol_event,
10474 .setup = alc883_medion_wim2160_setup,
10475 .init_hook = alc_automute_amp,
10476 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010477 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010478 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010479 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
10480 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10481 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010482 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10483 .channel_mode = alc883_3ST_2ch_modes,
10484 .input_mux = &alc883_capture_source,
10485 },
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -043010486 [ALC883_CLEVO_M540R] = {
10487 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10488 .init_verbs = { alc883_init_verbs, alc883_clevo_m540r_verbs },
10489 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10490 .dac_nids = alc883_dac_nids,
10491 .dig_out_nid = ALC883_DIGOUT_NID,
10492 .dig_in_nid = ALC883_DIGIN_NID,
10493 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_clevo_modes),
10494 .channel_mode = alc883_3ST_6ch_clevo_modes,
10495 .need_dac_fix = 1,
10496 .input_mux = &alc883_capture_source,
10497 /* This machine has the hardware HP auto-muting, thus
10498 * we need no software mute via unsol event
10499 */
10500 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010501 [ALC883_CLEVO_M720] = {
10502 .mixers = { alc883_clevo_m720_mixer },
10503 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +010010504 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10505 .dac_nids = alc883_dac_nids,
10506 .dig_out_nid = ALC883_DIGOUT_NID,
10507 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10508 .channel_mode = alc883_3ST_2ch_modes,
10509 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010510 .unsol_event = alc883_clevo_m720_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010511 .setup = alc883_clevo_m720_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010512 .init_hook = alc883_clevo_m720_init_hook,
Jiang zhe368c7a92008-03-04 11:20:33 +010010513 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010514 [ALC883_LENOVO_101E_2ch] = {
10515 .mixers = { alc883_lenovo_101e_2ch_mixer},
10516 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
10517 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10518 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010519 .adc_nids = alc883_adc_nids_alt,
10520 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010521 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010522 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10523 .channel_mode = alc883_3ST_2ch_modes,
10524 .input_mux = &alc883_lenovo_101e_capture_source,
10525 .unsol_event = alc883_lenovo_101e_unsol_event,
10526 .init_hook = alc883_lenovo_101e_all_automute,
10527 },
Kailang Yang272a5272007-05-14 11:00:38 +020010528 [ALC883_LENOVO_NB0763] = {
10529 .mixers = { alc883_lenovo_nb0763_mixer },
10530 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
10531 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10532 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020010533 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10534 .channel_mode = alc883_3ST_2ch_modes,
10535 .need_dac_fix = 1,
10536 .input_mux = &alc883_lenovo_nb0763_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010537 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwaidc427172010-11-29 07:42:59 +010010538 .setup = alc883_lenovo_nb0763_setup,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010539 .init_hook = alc_automute_amp,
Kailang Yang272a5272007-05-14 11:00:38 +020010540 },
10541 [ALC888_LENOVO_MS7195_DIG] = {
10542 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10543 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
10544 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10545 .dac_nids = alc883_dac_nids,
10546 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +020010547 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10548 .channel_mode = alc883_3ST_6ch_modes,
10549 .need_dac_fix = 1,
10550 .input_mux = &alc883_capture_source,
10551 .unsol_event = alc883_lenovo_ms7195_unsol_event,
10552 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +020010553 },
10554 [ALC883_HAIER_W66] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010555 .mixers = { alc883_targa_2ch_mixer},
Kailang Yang189609a2007-08-20 11:31:23 +020010556 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
10557 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10558 .dac_nids = alc883_dac_nids,
10559 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +020010560 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10561 .channel_mode = alc883_3ST_2ch_modes,
10562 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010563 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010564 .setup = alc883_haier_w66_setup,
10565 .init_hook = alc_automute_amp,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +010010566 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010567 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +010010568 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010569 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010570 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10571 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010572 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
10573 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010574 .need_dac_fix = 1,
10575 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010576 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010577 .setup = alc888_3st_hp_setup,
10578 .init_hook = alc_automute_amp,
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010579 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010580 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +010010581 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010582 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
10583 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10584 .dac_nids = alc883_dac_nids,
10585 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010586 .dig_in_nid = ALC883_DIGIN_NID,
10587 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10588 .channel_mode = alc883_sixstack_modes,
10589 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010590 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010591 .setup = alc888_6st_dell_setup,
10592 .init_hook = alc_automute_amp,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010593 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010594 [ALC883_MITAC] = {
10595 .mixers = { alc883_mitac_mixer },
10596 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
10597 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10598 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010599 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10600 .channel_mode = alc883_3ST_2ch_modes,
10601 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010602 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010603 .setup = alc883_mitac_setup,
10604 .init_hook = alc_automute_amp,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010605 },
Jiang zhefb97dc62008-03-06 11:07:11 +010010606 [ALC883_FUJITSU_PI2515] = {
10607 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
10608 .init_verbs = { alc883_init_verbs,
10609 alc883_2ch_fujitsu_pi2515_verbs},
10610 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10611 .dac_nids = alc883_dac_nids,
10612 .dig_out_nid = ALC883_DIGOUT_NID,
10613 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10614 .channel_mode = alc883_3ST_2ch_modes,
10615 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010616 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010617 .setup = alc883_2ch_fujitsu_pi2515_setup,
10618 .init_hook = alc_automute_amp,
Jiang zhefb97dc62008-03-06 11:07:11 +010010619 },
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010620 [ALC888_FUJITSU_XA3530] = {
10621 .mixers = { alc888_base_mixer, alc883_chmode_mixer },
10622 .init_verbs = { alc883_init_verbs,
10623 alc888_fujitsu_xa3530_verbs },
10624 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10625 .dac_nids = alc883_dac_nids,
10626 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10627 .adc_nids = alc883_adc_nids_rev,
10628 .capsrc_nids = alc883_capsrc_nids_rev,
10629 .dig_out_nid = ALC883_DIGOUT_NID,
10630 .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes),
10631 .channel_mode = alc888_4ST_8ch_intel_modes,
10632 .num_mux_defs =
10633 ARRAY_SIZE(alc888_2_capture_sources),
10634 .input_mux = alc888_2_capture_sources,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010635 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010636 .setup = alc888_fujitsu_xa3530_setup,
10637 .init_hook = alc_automute_amp,
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010638 },
Kailang Yange2757d52008-08-26 13:17:46 +020010639 [ALC888_LENOVO_SKY] = {
10640 .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
10641 .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
10642 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10643 .dac_nids = alc883_dac_nids,
10644 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yange2757d52008-08-26 13:17:46 +020010645 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10646 .channel_mode = alc883_sixstack_modes,
10647 .need_dac_fix = 1,
10648 .input_mux = &alc883_lenovo_sky_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010649 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010650 .setup = alc888_lenovo_sky_setup,
10651 .init_hook = alc_automute_amp,
Kailang Yange2757d52008-08-26 13:17:46 +020010652 },
10653 [ALC888_ASUS_M90V] = {
10654 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10655 .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
10656 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10657 .dac_nids = alc883_dac_nids,
10658 .dig_out_nid = ALC883_DIGOUT_NID,
10659 .dig_in_nid = ALC883_DIGIN_NID,
10660 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10661 .channel_mode = alc883_3ST_6ch_modes,
10662 .need_dac_fix = 1,
10663 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010664 .unsol_event = alc_sku_unsol_event,
10665 .setup = alc883_mode2_setup,
10666 .init_hook = alc_inithook,
Kailang Yange2757d52008-08-26 13:17:46 +020010667 },
10668 [ALC888_ASUS_EEE1601] = {
10669 .mixers = { alc883_asus_eee1601_mixer },
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010670 .cap_mixer = alc883_asus_eee1601_cap_mixer,
Kailang Yange2757d52008-08-26 13:17:46 +020010671 .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
10672 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10673 .dac_nids = alc883_dac_nids,
10674 .dig_out_nid = ALC883_DIGOUT_NID,
10675 .dig_in_nid = ALC883_DIGIN_NID,
10676 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10677 .channel_mode = alc883_3ST_2ch_modes,
10678 .need_dac_fix = 1,
10679 .input_mux = &alc883_asus_eee1601_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010680 .unsol_event = alc_sku_unsol_event,
Kailang Yange2757d52008-08-26 13:17:46 +020010681 .init_hook = alc883_eee1601_inithook,
10682 },
Wu Fengguang3ab90932008-11-17 09:51:09 +010010683 [ALC1200_ASUS_P5Q] = {
10684 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
10685 .init_verbs = { alc883_init_verbs },
10686 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10687 .dac_nids = alc883_dac_nids,
10688 .dig_out_nid = ALC1200_DIGOUT_NID,
10689 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangb25c9da2009-02-06 15:02:27 +080010690 .slave_dig_outs = alc1200_slave_dig_outs,
Wu Fengguang3ab90932008-11-17 09:51:09 +010010691 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10692 .channel_mode = alc883_sixstack_modes,
10693 .input_mux = &alc883_capture_source,
10694 },
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010695 [ALC889A_MB31] = {
10696 .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer},
10697 .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs,
10698 alc880_gpio1_init_verbs },
10699 .adc_nids = alc883_adc_nids,
10700 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010701 .capsrc_nids = alc883_capsrc_nids,
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010702 .dac_nids = alc883_dac_nids,
10703 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10704 .channel_mode = alc889A_mb31_6ch_modes,
10705 .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes),
10706 .input_mux = &alc889A_mb31_capture_source,
10707 .dig_out_nid = ALC883_DIGOUT_NID,
10708 .unsol_event = alc889A_mb31_unsol_event,
10709 .init_hook = alc889A_mb31_automute,
10710 },
Guido Günther3e1647c2009-06-05 00:47:26 +020010711 [ALC883_SONY_VAIO_TT] = {
10712 .mixers = { alc883_vaiott_mixer },
10713 .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs },
10714 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10715 .dac_nids = alc883_dac_nids,
10716 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10717 .channel_mode = alc883_3ST_2ch_modes,
10718 .input_mux = &alc883_capture_source,
10719 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010720 .setup = alc883_vaiott_setup,
10721 .init_hook = alc_automute_amp,
Guido Günther3e1647c2009-06-05 00:47:26 +020010722 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010723};
10724
10725
10726/*
Takashi Iwai49535502009-06-30 15:28:30 +020010727 * Pin config fixes
10728 */
10729enum {
Takashi Iwai954a29c2010-07-30 10:55:44 +020010730 PINFIX_ABIT_AW9D_MAX,
10731 PINFIX_PB_M5210,
David Henningssonc3d226a2010-10-14 15:42:08 +020010732 PINFIX_ACER_ASPIRE_7736,
Takashi Iwai49535502009-06-30 15:28:30 +020010733};
10734
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010735static const struct alc_fixup alc882_fixups[] = {
10736 [PINFIX_ABIT_AW9D_MAX] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010010737 .type = ALC_FIXUP_PINS,
10738 .v.pins = (const struct alc_pincfg[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020010739 { 0x15, 0x01080104 }, /* side */
10740 { 0x16, 0x01011012 }, /* rear */
10741 { 0x17, 0x01016011 }, /* clfe */
10742 { }
10743 }
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010744 },
Takashi Iwai954a29c2010-07-30 10:55:44 +020010745 [PINFIX_PB_M5210] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010010746 .type = ALC_FIXUP_VERBS,
10747 .v.verbs = (const struct hda_verb[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020010748 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
10749 {}
10750 }
Takashi Iwai954a29c2010-07-30 10:55:44 +020010751 },
David Henningssonc3d226a2010-10-14 15:42:08 +020010752 [PINFIX_ACER_ASPIRE_7736] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010010753 .type = ALC_FIXUP_SKU,
10754 .v.sku = ALC_FIXUP_SKU_IGNORE,
David Henningssonc3d226a2010-10-14 15:42:08 +020010755 },
Takashi Iwai49535502009-06-30 15:28:30 +020010756};
10757
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010758static struct snd_pci_quirk alc882_fixup_tbl[] = {
Takashi Iwai954a29c2010-07-30 10:55:44 +020010759 SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
Takashi Iwai49535502009-06-30 15:28:30 +020010760 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
David Henningssonc3d226a2010-10-14 15:42:08 +020010761 SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736),
Takashi Iwai49535502009-06-30 15:28:30 +020010762 {}
10763};
10764
10765/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010766 * BIOS auto configuration
10767 */
Takashi Iwai05f5f472009-08-25 13:10:18 +020010768static int alc882_auto_create_input_ctls(struct hda_codec *codec,
10769 const struct auto_pin_cfg *cfg)
10770{
10771 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x23, 0x22);
10772}
10773
Takashi Iwai49535502009-06-30 15:28:30 +020010774static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010775 hda_nid_t nid, int pin_type,
Takashi Iwai489008c2010-04-07 09:06:00 +020010776 hda_nid_t dac)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010777{
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010778 int idx;
10779
Takashi Iwai489008c2010-04-07 09:06:00 +020010780 /* set as output */
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010781 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010782
Takashi Iwai489008c2010-04-07 09:06:00 +020010783 if (dac == 0x25)
10784 idx = 4;
10785 else if (dac >= 0x02 && dac <= 0x05)
10786 idx = dac - 2;
10787 else
10788 return;
10789 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010790}
10791
Takashi Iwai49535502009-06-30 15:28:30 +020010792static void alc882_auto_init_multi_out(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010793{
10794 struct alc_spec *spec = codec->spec;
10795 int i;
10796
10797 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010798 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020010799 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010800 if (nid)
Takashi Iwai49535502009-06-30 15:28:30 +020010801 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai489008c2010-04-07 09:06:00 +020010802 spec->multiout.dac_nids[i]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010803 }
10804}
10805
Takashi Iwai49535502009-06-30 15:28:30 +020010806static void alc882_auto_init_hp_out(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010807{
10808 struct alc_spec *spec = codec->spec;
Takashi Iwai489008c2010-04-07 09:06:00 +020010809 hda_nid_t pin, dac;
Takashi Iwai5855fb82010-09-16 18:24:02 +020010810 int i;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010811
Takashi Iwai5855fb82010-09-16 18:24:02 +020010812 for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
10813 pin = spec->autocfg.hp_pins[i];
10814 if (!pin)
10815 break;
Takashi Iwai489008c2010-04-07 09:06:00 +020010816 dac = spec->multiout.hp_nid;
10817 if (!dac)
10818 dac = spec->multiout.dac_nids[0]; /* to front */
10819 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
10820 }
Takashi Iwai5855fb82010-09-16 18:24:02 +020010821 for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
10822 pin = spec->autocfg.speaker_pins[i];
10823 if (!pin)
10824 break;
Takashi Iwai489008c2010-04-07 09:06:00 +020010825 dac = spec->multiout.extra_out_nid[0];
10826 if (!dac)
10827 dac = spec->multiout.dac_nids[0]; /* to front */
10828 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
10829 }
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010830}
10831
Takashi Iwai49535502009-06-30 15:28:30 +020010832static void alc882_auto_init_analog_input(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010833{
10834 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010835 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010836 int i;
10837
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010838 for (i = 0; i < cfg->num_inputs; i++) {
10839 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai30ea0982010-09-16 18:47:56 +020010840 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwai49535502009-06-30 15:28:30 +020010841 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
10842 snd_hda_codec_write(codec, nid, 0,
10843 AC_VERB_SET_AMP_GAIN_MUTE,
10844 AMP_OUT_MUTE);
10845 }
10846}
10847
10848static void alc882_auto_init_input_src(struct hda_codec *codec)
10849{
10850 struct alc_spec *spec = codec->spec;
10851 int c;
10852
10853 for (c = 0; c < spec->num_adc_nids; c++) {
10854 hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
10855 hda_nid_t nid = spec->capsrc_nids[c];
10856 unsigned int mux_idx;
10857 const struct hda_input_mux *imux;
10858 int conns, mute, idx, item;
10859
10860 conns = snd_hda_get_connections(codec, nid, conn_list,
10861 ARRAY_SIZE(conn_list));
10862 if (conns < 0)
10863 continue;
10864 mux_idx = c >= spec->num_mux_defs ? 0 : c;
10865 imux = &spec->input_mux[mux_idx];
Takashi Iwai53111142010-03-08 12:13:07 +010010866 if (!imux->num_items && mux_idx > 0)
10867 imux = &spec->input_mux[0];
Takashi Iwai49535502009-06-30 15:28:30 +020010868 for (idx = 0; idx < conns; idx++) {
10869 /* if the current connection is the selected one,
10870 * unmute it as default - otherwise mute it
10871 */
10872 mute = AMP_IN_MUTE(idx);
10873 for (item = 0; item < imux->num_items; item++) {
10874 if (imux->items[item].index == idx) {
10875 if (spec->cur_mux[c] == item)
10876 mute = AMP_IN_UNMUTE(idx);
10877 break;
10878 }
10879 }
10880 /* check if we have a selector or mixer
10881 * we could check for the widget type instead, but
10882 * just check for Amp-In presence (in case of mixer
10883 * without amp-in there is something wrong, this
10884 * function shouldn't be used or capsrc nid is wrong)
10885 */
10886 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010887 snd_hda_codec_write(codec, nid, 0,
10888 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwai49535502009-06-30 15:28:30 +020010889 mute);
10890 else if (mute != AMP_IN_MUTE(idx))
10891 snd_hda_codec_write(codec, nid, 0,
10892 AC_VERB_SET_CONNECT_SEL,
10893 idx);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010894 }
10895 }
10896}
10897
Takashi Iwai49535502009-06-30 15:28:30 +020010898/* add mic boosts if needed */
10899static int alc_auto_add_mic_boost(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010900{
10901 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010902 struct auto_pin_cfg *cfg = &spec->autocfg;
David Henningsson5322bf22011-01-05 11:03:56 +010010903 int i, err;
Takashi Iwai53e8c322010-12-17 15:23:41 +010010904 int type_idx = 0;
Takashi Iwai49535502009-06-30 15:28:30 +020010905 hda_nid_t nid;
David Henningsson5322bf22011-01-05 11:03:56 +010010906 const char *prev_label = NULL;
Takashi Iwai49535502009-06-30 15:28:30 +020010907
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010908 for (i = 0; i < cfg->num_inputs; i++) {
Takashi Iwai86e29592010-09-09 14:50:17 +020010909 if (cfg->inputs[i].type > AUTO_PIN_MIC)
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010910 break;
10911 nid = cfg->inputs[i].pin;
10912 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
David Henningsson5322bf22011-01-05 11:03:56 +010010913 const char *label;
10914 char boost_label[32];
10915
10916 label = hda_get_autocfg_input_label(codec, cfg, i);
10917 if (prev_label && !strcmp(label, prev_label))
Takashi Iwai53e8c322010-12-17 15:23:41 +010010918 type_idx++;
10919 else
10920 type_idx = 0;
David Henningsson5322bf22011-01-05 11:03:56 +010010921 prev_label = label;
10922
10923 snprintf(boost_label, sizeof(boost_label),
10924 "%s Boost Volume", label);
10925 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10926 boost_label, type_idx,
Takashi Iwai49535502009-06-30 15:28:30 +020010927 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010928 if (err < 0)
10929 return err;
10930 }
Takashi Iwai49535502009-06-30 15:28:30 +020010931 }
10932 return 0;
10933}
10934
10935/* almost identical with ALC880 parser... */
10936static int alc882_parse_auto_config(struct hda_codec *codec)
10937{
10938 struct alc_spec *spec = codec->spec;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010939 static hda_nid_t alc882_ignore[] = { 0x1d, 0 };
Takashi Iwai757899a2010-07-30 10:48:14 +020010940 int err;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010941
Takashi Iwai05f5f472009-08-25 13:10:18 +020010942 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10943 alc882_ignore);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010944 if (err < 0)
10945 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010946 if (!spec->autocfg.line_outs)
10947 return 0; /* can't find valid BIOS pin config */
10948
10949 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
10950 if (err < 0)
10951 return err;
Takashi Iwai569ed342011-01-19 10:14:46 +010010952 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
Takashi Iwai05f5f472009-08-25 13:10:18 +020010953 if (err < 0)
10954 return err;
Takashi Iwai489008c2010-04-07 09:06:00 +020010955 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
10956 "Headphone");
10957 if (err < 0)
10958 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010959 err = alc880_auto_create_extra_out(spec,
10960 spec->autocfg.speaker_pins[0],
10961 "Speaker");
10962 if (err < 0)
10963 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010964 err = alc882_auto_create_input_ctls(codec, &spec->autocfg);
10965 if (err < 0)
10966 return err;
10967
10968 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10969
Takashi Iwai757899a2010-07-30 10:48:14 +020010970 alc_auto_parse_digital(codec);
Takashi Iwai05f5f472009-08-25 13:10:18 +020010971
10972 if (spec->kctls.list)
10973 add_mixer(spec, spec->kctls.list);
10974
10975 add_verb(spec, alc883_auto_init_verbs);
10976 /* if ADC 0x07 is available, initialize it, too */
10977 if (get_wcaps_type(get_wcaps(codec, 0x07)) == AC_WID_AUD_IN)
10978 add_verb(spec, alc882_adc1_init_verbs);
10979
10980 spec->num_mux_defs = 1;
10981 spec->input_mux = &spec->private_imux[0];
10982
Kailang Yang6227cdc2010-02-25 08:36:52 +010010983 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai776e1842007-08-29 15:07:11 +020010984
10985 err = alc_auto_add_mic_boost(codec);
10986 if (err < 0)
10987 return err;
10988
Takashi Iwai776e1842007-08-29 15:07:11 +020010989 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010990}
10991
10992/* additional initialization for auto-configuration model */
Takashi Iwai49535502009-06-30 15:28:30 +020010993static void alc882_auto_init(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010994{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010995 struct alc_spec *spec = codec->spec;
Takashi Iwai49535502009-06-30 15:28:30 +020010996 alc882_auto_init_multi_out(codec);
10997 alc882_auto_init_hp_out(codec);
10998 alc882_auto_init_analog_input(codec);
10999 alc882_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020011000 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011001 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020011002 alc_inithook(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011003}
11004
Takashi Iwai49535502009-06-30 15:28:30 +020011005static int patch_alc882(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011006{
11007 struct alc_spec *spec;
11008 int err, board_config;
11009
11010 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
11011 if (spec == NULL)
11012 return -ENOMEM;
11013
11014 codec->spec = spec;
11015
Takashi Iwai49535502009-06-30 15:28:30 +020011016 switch (codec->vendor_id) {
11017 case 0x10ec0882:
11018 case 0x10ec0885:
11019 break;
11020 default:
11021 /* ALC883 and variants */
11022 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
11023 break;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011024 }
11025
Takashi Iwai49535502009-06-30 15:28:30 +020011026 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
11027 alc882_models,
11028 alc882_cfg_tbl);
11029
11030 if (board_config < 0 || board_config >= ALC882_MODEL_LAST)
11031 board_config = snd_hda_check_board_codec_sid_config(codec,
11032 ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
11033
11034 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020011035 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai49535502009-06-30 15:28:30 +020011036 codec->chip_name);
11037 board_config = ALC882_AUTO;
11038 }
11039
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010011040 if (board_config == ALC882_AUTO) {
11041 alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups);
11042 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
11043 }
Takashi Iwai49535502009-06-30 15:28:30 +020011044
David Henningsson90622912010-10-14 14:50:18 +020011045 alc_auto_parse_customize_define(codec);
11046
Takashi Iwai49535502009-06-30 15:28:30 +020011047 if (board_config == ALC882_AUTO) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011048 /* automatic parse from the BIOS config */
Takashi Iwai49535502009-06-30 15:28:30 +020011049 err = alc882_parse_auto_config(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011050 if (err < 0) {
11051 alc_free(codec);
11052 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011053 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011054 printk(KERN_INFO
11055 "hda_codec: Cannot set up configuration "
11056 "from BIOS. Using base mode...\n");
Takashi Iwai49535502009-06-30 15:28:30 +020011057 board_config = ALC882_3ST_DIG;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011058 }
11059 }
11060
Takashi Iwaidc1eae22010-07-29 15:30:02 +020011061 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020011062 err = snd_hda_attach_beep_device(codec, 0x1);
11063 if (err < 0) {
11064 alc_free(codec);
11065 return err;
11066 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090011067 }
11068
Takashi Iwai49535502009-06-30 15:28:30 +020011069 if (board_config != ALC882_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020011070 setup_preset(codec, &alc882_presets[board_config]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011071
Takashi Iwai49535502009-06-30 15:28:30 +020011072 spec->stream_analog_playback = &alc882_pcm_analog_playback;
11073 spec->stream_analog_capture = &alc882_pcm_analog_capture;
11074 /* FIXME: setup DAC5 */
11075 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
11076 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
11077
11078 spec->stream_digital_playback = &alc882_pcm_digital_playback;
11079 spec->stream_digital_capture = &alc882_pcm_digital_capture;
11080
Takashi Iwai49535502009-06-30 15:28:30 +020011081 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010011082 int i, j;
Takashi Iwai49535502009-06-30 15:28:30 +020011083 spec->num_adc_nids = 0;
11084 for (i = 0; i < ARRAY_SIZE(alc882_adc_nids); i++) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010011085 const struct hda_input_mux *imux = spec->input_mux;
Takashi Iwai49535502009-06-30 15:28:30 +020011086 hda_nid_t cap;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010011087 hda_nid_t items[16];
Takashi Iwai49535502009-06-30 15:28:30 +020011088 hda_nid_t nid = alc882_adc_nids[i];
11089 unsigned int wcap = get_wcaps(codec, nid);
11090 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020011091 wcap = get_wcaps_type(wcap);
Takashi Iwai49535502009-06-30 15:28:30 +020011092 if (wcap != AC_WID_AUD_IN)
11093 continue;
11094 spec->private_adc_nids[spec->num_adc_nids] = nid;
11095 err = snd_hda_get_connections(codec, nid, &cap, 1);
11096 if (err < 0)
11097 continue;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010011098 err = snd_hda_get_connections(codec, cap, items,
11099 ARRAY_SIZE(items));
11100 if (err < 0)
11101 continue;
11102 for (j = 0; j < imux->num_items; j++)
11103 if (imux->items[j].index >= err)
11104 break;
11105 if (j < imux->num_items)
11106 continue;
Takashi Iwai49535502009-06-30 15:28:30 +020011107 spec->private_capsrc_nids[spec->num_adc_nids] = cap;
11108 spec->num_adc_nids++;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020011109 }
Takashi Iwai49535502009-06-30 15:28:30 +020011110 spec->adc_nids = spec->private_adc_nids;
11111 spec->capsrc_nids = spec->private_capsrc_nids;
Kailang Yang2f893282008-05-27 12:14:47 +020011112 }
11113
Takashi Iwaib59bdf32009-08-11 09:47:30 +020011114 set_capture_mixer(codec);
Kailang Yangda00c242010-03-19 11:23:45 +010011115
Takashi Iwaidc1eae22010-07-29 15:30:02 +020011116 if (has_cdefine_beep(codec))
Kailang Yangda00c242010-03-19 11:23:45 +010011117 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011118
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010011119 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwai7fa90e82010-04-12 08:49:00 +020011120
Takashi Iwai2134ea42008-01-10 16:53:55 +010011121 spec->vmaster_nid = 0x0c;
11122
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011123 codec->patch_ops = alc_patch_ops;
Takashi Iwai49535502009-06-30 15:28:30 +020011124 if (board_config == ALC882_AUTO)
11125 spec->init_hook = alc882_auto_init;
Kailang Yangbf1b0222010-10-21 08:49:56 +020011126
11127 alc_init_jacks(codec);
Takashi Iwaicb53c622007-08-10 17:21:45 +020011128#ifdef CONFIG_SND_HDA_POWER_SAVE
11129 if (!spec->loopback.amplist)
Takashi Iwai49535502009-06-30 15:28:30 +020011130 spec->loopback.amplist = alc882_loopbacks;
Takashi Iwaicb53c622007-08-10 17:21:45 +020011131#endif
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011132
11133 return 0;
11134}
11135
Takashi Iwai49535502009-06-30 15:28:30 +020011136
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011137/*
Kailang Yangdf694da2005-12-05 19:42:22 +010011138 * ALC262 support
11139 */
11140
11141#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
11142#define ALC262_DIGIN_NID ALC880_DIGIN_NID
11143
11144#define alc262_dac_nids alc260_dac_nids
11145#define alc262_adc_nids alc882_adc_nids
11146#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +010011147#define alc262_capsrc_nids alc882_capsrc_nids
11148#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +010011149
11150#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +010011151#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +010011152
Kailang Yang4e555fe2008-08-26 13:05:55 +020011153static hda_nid_t alc262_dmic_adc_nids[1] = {
11154 /* ADC0 */
11155 0x09
11156};
11157
11158static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
11159
Kailang Yangdf694da2005-12-05 19:42:22 +010011160static struct snd_kcontrol_new alc262_base_mixer[] = {
11161 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11162 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11163 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11164 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11165 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11166 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11167 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11168 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011169 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011170 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11171 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011172 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011173 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
11174 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11175 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
11176 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011177 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +010011178};
11179
Takashi Iwaice875f02008-01-28 18:17:43 +010011180/* update HP, line and mono-out pins according to the master switch */
11181static void alc262_hp_master_update(struct hda_codec *codec)
11182{
11183 struct alc_spec *spec = codec->spec;
11184 int val = spec->master_sw;
11185
11186 /* HP & line-out */
11187 snd_hda_codec_write_cache(codec, 0x1b, 0,
11188 AC_VERB_SET_PIN_WIDGET_CONTROL,
11189 val ? PIN_HP : 0);
11190 snd_hda_codec_write_cache(codec, 0x15, 0,
11191 AC_VERB_SET_PIN_WIDGET_CONTROL,
11192 val ? PIN_HP : 0);
11193 /* mono (speaker) depending on the HP jack sense */
11194 val = val && !spec->jack_present;
11195 snd_hda_codec_write_cache(codec, 0x16, 0,
11196 AC_VERB_SET_PIN_WIDGET_CONTROL,
11197 val ? PIN_OUT : 0);
11198}
11199
11200static void alc262_hp_bpc_automute(struct hda_codec *codec)
11201{
11202 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080011203
11204 spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
Takashi Iwaice875f02008-01-28 18:17:43 +010011205 alc262_hp_master_update(codec);
11206}
11207
11208static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
11209{
11210 if ((res >> 26) != ALC880_HP_EVENT)
11211 return;
11212 alc262_hp_bpc_automute(codec);
11213}
11214
11215static void alc262_hp_wildwest_automute(struct hda_codec *codec)
11216{
11217 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080011218
11219 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaice875f02008-01-28 18:17:43 +010011220 alc262_hp_master_update(codec);
11221}
11222
11223static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
11224 unsigned int res)
11225{
11226 if ((res >> 26) != ALC880_HP_EVENT)
11227 return;
11228 alc262_hp_wildwest_automute(codec);
11229}
11230
Takashi Iwaib72519b2009-05-08 14:31:55 +020011231#define alc262_hp_master_sw_get alc260_hp_master_sw_get
Takashi Iwaice875f02008-01-28 18:17:43 +010011232
11233static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
11234 struct snd_ctl_elem_value *ucontrol)
11235{
11236 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11237 struct alc_spec *spec = codec->spec;
11238 int val = !!*ucontrol->value.integer.value;
11239
11240 if (val == spec->master_sw)
11241 return 0;
11242 spec->master_sw = val;
11243 alc262_hp_master_update(codec);
11244 return 1;
11245}
11246
Takashi Iwaib72519b2009-05-08 14:31:55 +020011247#define ALC262_HP_MASTER_SWITCH \
11248 { \
11249 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
11250 .name = "Master Playback Switch", \
11251 .info = snd_ctl_boolean_mono_info, \
11252 .get = alc262_hp_master_sw_get, \
11253 .put = alc262_hp_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011254 }, \
11255 { \
11256 .iface = NID_MAPPING, \
11257 .name = "Master Playback Switch", \
11258 .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \
Takashi Iwaib72519b2009-05-08 14:31:55 +020011259 }
11260
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011261
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011262static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020011263 ALC262_HP_MASTER_SWITCH,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011264 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11265 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11266 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010011267 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
11268 HDA_OUTPUT),
11269 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
11270 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011271 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11272 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011273 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011274 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11275 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011276 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011277 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("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11280 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011281 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
11282 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
11283 { } /* end */
11284};
11285
Kailang Yangcd7509a2007-01-26 18:33:17 +010011286static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020011287 ALC262_HP_MASTER_SWITCH,
Kailang Yangcd7509a2007-01-26 18:33:17 +010011288 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11289 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
11290 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11291 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010011292 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
11293 HDA_OUTPUT),
11294 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
11295 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011296 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
11297 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011298 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011299 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
11300 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
11301 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11302 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011303 { } /* end */
11304};
11305
11306static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
11307 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11308 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011309 HDA_CODEC_VOLUME("Rear Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011310 { } /* end */
11311};
11312
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011313/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011314static void alc262_hp_t5735_setup(struct hda_codec *codec)
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011315{
11316 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011317
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011318 spec->autocfg.hp_pins[0] = 0x15;
Takashi Iwaidc99be42010-01-20 08:35:06 +010011319 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011320}
11321
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011322static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010011323 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11324 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011325 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11326 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11327 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11328 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011329 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011330 { } /* end */
11331};
11332
11333static struct hda_verb alc262_hp_t5735_verbs[] = {
11334 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11335 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11336
11337 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11338 { }
11339};
11340
Kailang Yang8c427222008-01-10 13:03:59 +010011341static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +010011342 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11343 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010011344 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
11345 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010011346 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
11347 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
11348 { } /* end */
11349};
11350
11351static struct hda_verb alc262_hp_rp5700_verbs[] = {
11352 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11353 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11354 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11355 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11356 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11357 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11358 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11359 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11360 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
11361 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
11362 {}
11363};
11364
11365static struct hda_input_mux alc262_hp_rp5700_capture_source = {
11366 .num_items = 1,
11367 .items = {
11368 { "Line", 0x1 },
11369 },
11370};
11371
Takashi Iwai42171c12009-05-08 14:11:43 +020011372/* bind hp and internal speaker mute (with plug check) as master switch */
11373static void alc262_hippo_master_update(struct hda_codec *codec)
11374{
11375 struct alc_spec *spec = codec->spec;
11376 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
11377 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
11378 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
11379 unsigned int mute;
11380
11381 /* HP */
11382 mute = spec->master_sw ? 0 : HDA_AMP_MUTE;
11383 snd_hda_codec_amp_stereo(codec, hp_nid, HDA_OUTPUT, 0,
11384 HDA_AMP_MUTE, mute);
11385 /* mute internal speaker per jack sense */
11386 if (spec->jack_present)
11387 mute = HDA_AMP_MUTE;
11388 if (line_nid)
11389 snd_hda_codec_amp_stereo(codec, line_nid, HDA_OUTPUT, 0,
11390 HDA_AMP_MUTE, mute);
11391 if (speaker_nid && speaker_nid != line_nid)
11392 snd_hda_codec_amp_stereo(codec, speaker_nid, HDA_OUTPUT, 0,
11393 HDA_AMP_MUTE, mute);
11394}
11395
11396#define alc262_hippo_master_sw_get alc262_hp_master_sw_get
11397
11398static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol,
11399 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai0724ea22007-08-23 00:31:43 +020011400{
11401 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Takashi Iwai42171c12009-05-08 14:11:43 +020011402 struct alc_spec *spec = codec->spec;
11403 int val = !!*ucontrol->value.integer.value;
Takashi Iwai0724ea22007-08-23 00:31:43 +020011404
Takashi Iwai42171c12009-05-08 14:11:43 +020011405 if (val == spec->master_sw)
11406 return 0;
11407 spec->master_sw = val;
11408 alc262_hippo_master_update(codec);
11409 return 1;
Takashi Iwai0724ea22007-08-23 00:31:43 +020011410}
Takashi Iwai5b319542007-07-26 11:49:22 +020011411
Takashi Iwai42171c12009-05-08 14:11:43 +020011412#define ALC262_HIPPO_MASTER_SWITCH \
11413 { \
11414 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
11415 .name = "Master Playback Switch", \
11416 .info = snd_ctl_boolean_mono_info, \
11417 .get = alc262_hippo_master_sw_get, \
11418 .put = alc262_hippo_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011419 }, \
11420 { \
11421 .iface = NID_MAPPING, \
11422 .name = "Master Playback Switch", \
11423 .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \
11424 (SUBDEV_SPEAKER(0) << 16), \
Takashi Iwai42171c12009-05-08 14:11:43 +020011425 }
11426
11427static struct snd_kcontrol_new alc262_hippo_mixer[] = {
11428 ALC262_HIPPO_MASTER_SWITCH,
11429 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11430 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11431 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11432 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11433 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11434 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11435 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011436 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011437 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11438 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011439 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011440 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11441 { } /* end */
11442};
11443
11444static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
11445 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11446 ALC262_HIPPO_MASTER_SWITCH,
11447 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11448 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11449 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11450 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11451 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11452 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011453 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011454 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11455 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011456 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011457 { } /* end */
11458};
11459
11460/* mute/unmute internal speaker according to the hp jack and mute state */
11461static void alc262_hippo_automute(struct hda_codec *codec)
11462{
11463 struct alc_spec *spec = codec->spec;
11464 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
Takashi Iwai42171c12009-05-08 14:11:43 +020011465
Wu Fengguang864f92b2009-11-18 12:38:02 +080011466 spec->jack_present = snd_hda_jack_detect(codec, hp_nid);
Takashi Iwai42171c12009-05-08 14:11:43 +020011467 alc262_hippo_master_update(codec);
11468}
11469
11470static void alc262_hippo_unsol_event(struct hda_codec *codec, unsigned int res)
11471{
11472 if ((res >> 26) != ALC880_HP_EVENT)
11473 return;
11474 alc262_hippo_automute(codec);
11475}
11476
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011477static void alc262_hippo_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020011478{
11479 struct alc_spec *spec = codec->spec;
11480
11481 spec->autocfg.hp_pins[0] = 0x15;
11482 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai42171c12009-05-08 14:11:43 +020011483}
11484
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011485static void alc262_hippo1_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020011486{
11487 struct alc_spec *spec = codec->spec;
11488
11489 spec->autocfg.hp_pins[0] = 0x1b;
11490 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai42171c12009-05-08 14:11:43 +020011491}
11492
11493
Kailang Yang272a5272007-05-14 11:00:38 +020011494static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +020011495 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011496 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang272a5272007-05-14 11:00:38 +020011497 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11498 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11499 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11500 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11501 { } /* end */
11502};
11503
Kailang Yang83c34212007-07-05 11:43:05 +020011504static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011505 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11506 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang83c34212007-07-05 11:43:05 +020011507 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11508 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11509 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11510 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11511 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11512 { } /* end */
11513};
Kailang Yang272a5272007-05-14 11:00:38 +020011514
Tony Vroonba340e82009-02-02 19:01:30 +000011515static struct snd_kcontrol_new alc262_tyan_mixer[] = {
11516 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11517 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
11518 HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
11519 HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT),
11520 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11521 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11522 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11523 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011524 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tony Vroonba340e82009-02-02 19:01:30 +000011525 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11526 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011527 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Tony Vroonba340e82009-02-02 19:01:30 +000011528 { } /* end */
11529};
11530
11531static struct hda_verb alc262_tyan_verbs[] = {
11532 /* Headphone automute */
11533 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11534 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11535 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11536
11537 /* P11 AUX_IN, white 4-pin connector */
11538 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11539 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
11540 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
11541 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
11542
11543 {}
11544};
11545
11546/* unsolicited event for HP jack sensing */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011547static void alc262_tyan_setup(struct hda_codec *codec)
Tony Vroonba340e82009-02-02 19:01:30 +000011548{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011549 struct alc_spec *spec = codec->spec;
Tony Vroonba340e82009-02-02 19:01:30 +000011550
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011551 spec->autocfg.hp_pins[0] = 0x1b;
11552 spec->autocfg.speaker_pins[0] = 0x15;
Tony Vroonba340e82009-02-02 19:01:30 +000011553}
11554
Tony Vroonba340e82009-02-02 19:01:30 +000011555
Kailang Yangdf694da2005-12-05 19:42:22 +010011556#define alc262_capture_mixer alc882_capture_mixer
11557#define alc262_capture_alt_mixer alc882_capture_alt_mixer
11558
11559/*
11560 * generic initialization of ADC, input mixers and output mixers
11561 */
11562static struct hda_verb alc262_init_verbs[] = {
11563 /*
11564 * Unmute ADC0-2 and set the default input to mic-in
11565 */
11566 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11567 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11568 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11569 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11570 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11571 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11572
Takashi Iwaicb53c622007-08-10 17:21:45 +020011573 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010011574 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011575 * Note: PASD motherboards uses the Line In 2 as the input for
11576 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010011577 */
11578 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011579 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11580 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11581 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11582 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11583 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011584
11585 /*
11586 * Set up output mixers (0x0c - 0x0e)
11587 */
11588 /* set vol=0 to output mixers */
11589 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11590 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11591 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11592 /* set up input amps for analog loopback */
11593 /* Amp Indices: DAC = 0, mixer = 1 */
11594 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11595 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11596 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11597 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11598 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11599 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11600
11601 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11602 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11603 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11604 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11605 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11606 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11607
11608 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11609 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11610 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11611 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11612 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Kailang Yangea1fb292008-08-26 12:58:38 +020011613
Kailang Yangdf694da2005-12-05 19:42:22 +010011614 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11615 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Kailang Yangea1fb292008-08-26 12:58:38 +020011616
Kailang Yangdf694da2005-12-05 19:42:22 +010011617 /* FIXME: use matrix-type input source selection */
11618 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
11619 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
11620 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11621 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11622 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11623 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11624 /* Input mixer2 */
11625 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11626 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11627 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11628 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11629 /* Input mixer3 */
11630 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11631 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11632 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011633 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +010011634
11635 { }
11636};
11637
Kailang Yang4e555fe2008-08-26 13:05:55 +020011638static struct hda_verb alc262_eapd_verbs[] = {
11639 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
11640 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
11641 { }
11642};
11643
Kailang Yangccc656c2006-10-17 12:32:26 +020011644static struct hda_verb alc262_hippo1_unsol_verbs[] = {
11645 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11646 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11647 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11648
11649 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11650 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11651 {}
11652};
11653
Kailang Yang272a5272007-05-14 11:00:38 +020011654static struct hda_verb alc262_sony_unsol_verbs[] = {
11655 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11656 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11657 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
11658
11659 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11660 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +090011661 {}
Kailang Yang272a5272007-05-14 11:00:38 +020011662};
11663
Kailang Yang4e555fe2008-08-26 13:05:55 +020011664static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
11665 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11666 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11667 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11668 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11669 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang4e555fe2008-08-26 13:05:55 +020011670 { } /* end */
11671};
11672
11673static struct hda_verb alc262_toshiba_s06_verbs[] = {
11674 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11675 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11676 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11677 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11678 {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
11679 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11680 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11681 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11682 {}
11683};
11684
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011685static void alc262_toshiba_s06_setup(struct hda_codec *codec)
Kailang Yang4e555fe2008-08-26 13:05:55 +020011686{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011687 struct alc_spec *spec = codec->spec;
11688
11689 spec->autocfg.hp_pins[0] = 0x15;
11690 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011691 spec->ext_mic.pin = 0x18;
11692 spec->ext_mic.mux_idx = 0;
11693 spec->int_mic.pin = 0x12;
11694 spec->int_mic.mux_idx = 9;
11695 spec->auto_mic = 1;
Kailang Yang4e555fe2008-08-26 13:05:55 +020011696}
11697
Takashi Iwai834be882006-03-01 14:16:17 +010011698/*
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011699 * nec model
11700 * 0x15 = headphone
11701 * 0x16 = internal speaker
11702 * 0x18 = external mic
11703 */
11704
11705static struct snd_kcontrol_new alc262_nec_mixer[] = {
11706 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
11707 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
11708
11709 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11710 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011711 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011712
11713 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11714 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11715 { } /* end */
11716};
11717
11718static struct hda_verb alc262_nec_verbs[] = {
11719 /* Unmute Speaker */
11720 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11721
11722 /* Headphone */
11723 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11724 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11725
11726 /* External mic to headphone */
11727 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11728 /* External mic to speaker */
11729 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11730 {}
11731};
11732
11733/*
Takashi Iwai834be882006-03-01 14:16:17 +010011734 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +010011735 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
11736 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +010011737 */
11738
11739#define ALC_HP_EVENT 0x37
11740
11741static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
11742 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11743 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +010011744 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11745 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +010011746 {}
11747};
11748
Jiang zhe0e31daf2008-03-20 12:12:39 +010011749static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
11750 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11751 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11752 {}
11753};
11754
Daniel T Chene2595322009-12-19 18:19:02 -050011755static struct hda_verb alc262_lenovo_3000_init_verbs[] = {
11756 /* Front Mic pin: input vref at 50% */
11757 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
11758 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11759 {}
11760};
11761
Takashi Iwai834be882006-03-01 14:16:17 +010011762static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011763 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +010011764 .items = {
11765 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +010011766 { "Internal Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +010011767 { "CD", 0x4 },
11768 },
11769};
11770
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011771static struct hda_input_mux alc262_HP_capture_source = {
11772 .num_items = 5,
11773 .items = {
11774 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +020011775 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011776 { "Line", 0x2 },
11777 { "CD", 0x4 },
11778 { "AUX IN", 0x6 },
11779 },
11780};
11781
zhejiangaccbe492007-08-31 12:36:05 +020011782static struct hda_input_mux alc262_HP_D7000_capture_source = {
11783 .num_items = 4,
11784 .items = {
11785 { "Mic", 0x0 },
11786 { "Front Mic", 0x2 },
11787 { "Line", 0x1 },
11788 { "CD", 0x4 },
11789 },
11790};
11791
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011792/* mute/unmute internal speaker according to the hp jacks and mute state */
Takashi Iwai834be882006-03-01 14:16:17 +010011793static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
11794{
11795 struct alc_spec *spec = codec->spec;
11796 unsigned int mute;
11797
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011798 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011799 spec->jack_present = snd_hda_jack_detect(codec, 0x14) ||
11800 snd_hda_jack_detect(codec, 0x1b);
Takashi Iwai834be882006-03-01 14:16:17 +010011801 spec->sense_updated = 1;
11802 }
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011803 /* unmute internal speaker only if both HPs are unplugged and
11804 * master switch is on
11805 */
11806 if (spec->jack_present)
11807 mute = HDA_AMP_MUTE;
11808 else
Takashi Iwai834be882006-03-01 14:16:17 +010011809 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011810 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
11811 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +010011812}
11813
11814/* unsolicited event for HP jack sensing */
11815static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
11816 unsigned int res)
11817{
11818 if ((res >> 26) != ALC_HP_EVENT)
11819 return;
11820 alc262_fujitsu_automute(codec, 1);
11821}
11822
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011823static void alc262_fujitsu_init_hook(struct hda_codec *codec)
11824{
11825 alc262_fujitsu_automute(codec, 1);
11826}
11827
Takashi Iwai834be882006-03-01 14:16:17 +010011828/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +020011829static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
11830 .ops = &snd_hda_bind_vol,
11831 .values = {
11832 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
11833 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
11834 0
11835 },
11836};
Takashi Iwai834be882006-03-01 14:16:17 +010011837
Jiang zhe0e31daf2008-03-20 12:12:39 +010011838/* mute/unmute internal speaker according to the hp jack and mute state */
11839static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
11840{
11841 struct alc_spec *spec = codec->spec;
11842 unsigned int mute;
11843
11844 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011845 spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
Jiang zhe0e31daf2008-03-20 12:12:39 +010011846 spec->sense_updated = 1;
11847 }
11848 if (spec->jack_present) {
11849 /* mute internal speaker */
11850 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11851 HDA_AMP_MUTE, HDA_AMP_MUTE);
11852 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
11853 HDA_AMP_MUTE, HDA_AMP_MUTE);
11854 } else {
11855 /* unmute internal speaker if necessary */
11856 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
11857 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11858 HDA_AMP_MUTE, mute);
11859 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
11860 HDA_AMP_MUTE, mute);
11861 }
11862}
11863
11864/* unsolicited event for HP jack sensing */
11865static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
11866 unsigned int res)
11867{
11868 if ((res >> 26) != ALC_HP_EVENT)
11869 return;
11870 alc262_lenovo_3000_automute(codec, 1);
11871}
11872
Takashi Iwai8de56b72009-07-24 16:51:47 +020011873static int amp_stereo_mute_update(struct hda_codec *codec, hda_nid_t nid,
11874 int dir, int idx, long *valp)
11875{
11876 int i, change = 0;
11877
11878 for (i = 0; i < 2; i++, valp++)
11879 change |= snd_hda_codec_amp_update(codec, nid, i, dir, idx,
11880 HDA_AMP_MUTE,
11881 *valp ? 0 : HDA_AMP_MUTE);
11882 return change;
11883}
11884
Takashi Iwai834be882006-03-01 14:16:17 +010011885/* bind hp and internal speaker mute (with plug check) */
11886static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
11887 struct snd_ctl_elem_value *ucontrol)
11888{
11889 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11890 long *valp = ucontrol->value.integer.value;
11891 int change;
11892
Takashi Iwai8de56b72009-07-24 16:51:47 +020011893 change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
11894 change |= amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
Takashi Iwai82beb8f2007-08-10 17:09:26 +020011895 if (change)
11896 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +010011897 return change;
11898}
11899
11900static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +020011901 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +010011902 {
11903 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11904 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010011905 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwai834be882006-03-01 14:16:17 +010011906 .info = snd_hda_mixer_amp_switch_info,
11907 .get = snd_hda_mixer_amp_switch_get,
11908 .put = alc262_fujitsu_master_sw_put,
11909 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11910 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011911 {
11912 .iface = NID_MAPPING,
11913 .name = "Master Playback Switch",
11914 .private_value = 0x1b,
11915 },
Takashi Iwai834be882006-03-01 14:16:17 +010011916 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11917 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011918 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010011919 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11920 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011921 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +010011922 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11923 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010011924 { } /* end */
11925};
11926
Jiang zhe0e31daf2008-03-20 12:12:39 +010011927/* bind hp and internal speaker mute (with plug check) */
11928static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
11929 struct snd_ctl_elem_value *ucontrol)
11930{
11931 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11932 long *valp = ucontrol->value.integer.value;
11933 int change;
11934
Takashi Iwai8de56b72009-07-24 16:51:47 +020011935 change = amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
Jiang zhe0e31daf2008-03-20 12:12:39 +010011936 if (change)
11937 alc262_lenovo_3000_automute(codec, 0);
11938 return change;
11939}
11940
11941static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
11942 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
11943 {
11944 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11945 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010011946 .subdevice = HDA_SUBDEV_AMP_FLAG,
Jiang zhe0e31daf2008-03-20 12:12:39 +010011947 .info = snd_hda_mixer_amp_switch_info,
11948 .get = snd_hda_mixer_amp_switch_get,
11949 .put = alc262_lenovo_3000_master_sw_put,
11950 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
11951 },
11952 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11953 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011954 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhe0e31daf2008-03-20 12:12:39 +010011955 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11956 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011957 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +010011958 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11959 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe0e31daf2008-03-20 12:12:39 +010011960 { } /* end */
11961};
11962
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011963static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
11964 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai42171c12009-05-08 14:11:43 +020011965 ALC262_HIPPO_MASTER_SWITCH,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011966 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11967 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011968 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011969 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11970 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011971 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011972 { } /* end */
11973};
11974
Takashi Iwai304dcaa2006-07-25 14:51:16 +020011975/* additional init verbs for Benq laptops */
11976static struct hda_verb alc262_EAPD_verbs[] = {
11977 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
11978 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
11979 {}
11980};
11981
Kailang Yang83c34212007-07-05 11:43:05 +020011982static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
11983 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11984 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11985
11986 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
11987 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
11988 {}
11989};
11990
Tobin Davisf651b502007-10-26 12:40:47 +020011991/* Samsung Q1 Ultra Vista model setup */
11992static struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011993 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11994 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020011995 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11996 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011997 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
11998 HDA_CODEC_VOLUME("Headphone Mic Boost Volume", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020011999 { } /* end */
12000};
12001
12002static struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012003 /* output mixer */
12004 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12005 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12006 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12007 /* speaker */
12008 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12009 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12010 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12011 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
12012 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +020012013 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012014 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12015 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12016 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12017 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12018 /* internal mic */
12019 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12020 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12021 /* ADC, choose mic */
12022 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12023 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12024 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12025 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12026 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12027 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12028 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12029 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
12030 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
12031 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +020012032 {}
12033};
12034
Tobin Davisf651b502007-10-26 12:40:47 +020012035/* mute/unmute internal speaker according to the hp jack and mute state */
12036static void alc262_ultra_automute(struct hda_codec *codec)
12037{
12038 struct alc_spec *spec = codec->spec;
12039 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +020012040
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012041 mute = 0;
12042 /* auto-mute only when HP is used as HP */
12043 if (!spec->cur_mux[0]) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080012044 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012045 if (spec->jack_present)
12046 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +020012047 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012048 /* mute/unmute internal speaker */
12049 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
12050 HDA_AMP_MUTE, mute);
12051 /* mute/unmute HP */
12052 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
12053 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +020012054}
12055
12056/* unsolicited event for HP jack sensing */
12057static void alc262_ultra_unsol_event(struct hda_codec *codec,
12058 unsigned int res)
12059{
12060 if ((res >> 26) != ALC880_HP_EVENT)
12061 return;
12062 alc262_ultra_automute(codec);
12063}
12064
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012065static struct hda_input_mux alc262_ultra_capture_source = {
12066 .num_items = 2,
12067 .items = {
12068 { "Mic", 0x1 },
12069 { "Headphone", 0x7 },
12070 },
12071};
12072
12073static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
12074 struct snd_ctl_elem_value *ucontrol)
12075{
12076 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
12077 struct alc_spec *spec = codec->spec;
12078 int ret;
12079
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010012080 ret = alc_mux_enum_put(kcontrol, ucontrol);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012081 if (!ret)
12082 return 0;
12083 /* reprogram the HP pin as mic or HP according to the input source */
12084 snd_hda_codec_write_cache(codec, 0x15, 0,
12085 AC_VERB_SET_PIN_WIDGET_CONTROL,
12086 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
12087 alc262_ultra_automute(codec); /* mute/unmute HP */
12088 return ret;
12089}
12090
12091static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
12092 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
12093 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
12094 {
12095 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12096 .name = "Capture Source",
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010012097 .info = alc_mux_enum_info,
12098 .get = alc_mux_enum_get,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012099 .put = alc262_ultra_mux_enum_put,
12100 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010012101 {
12102 .iface = NID_MAPPING,
12103 .name = "Capture Source",
12104 .private_value = 0x15,
12105 },
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012106 { } /* end */
12107};
12108
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012109/* We use two mixers depending on the output pin; 0x16 is a mono output
12110 * and thus it's bound with a different mixer.
12111 * This function returns which mixer amp should be used.
12112 */
12113static int alc262_check_volbit(hda_nid_t nid)
12114{
12115 if (!nid)
12116 return 0;
12117 else if (nid == 0x16)
12118 return 2;
12119 else
12120 return 1;
12121}
12122
12123static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai033688a2010-09-08 15:47:09 +020012124 const char *pfx, int *vbits, int idx)
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012125{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012126 unsigned long val;
12127 int vbit;
12128
12129 vbit = alc262_check_volbit(nid);
12130 if (!vbit)
12131 return 0;
12132 if (*vbits & vbit) /* a volume control for this mixer already there */
12133 return 0;
12134 *vbits |= vbit;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012135 if (vbit == 2)
12136 val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT);
12137 else
12138 val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT);
Takashi Iwai033688a2010-09-08 15:47:09 +020012139 return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012140}
12141
12142static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai033688a2010-09-08 15:47:09 +020012143 const char *pfx, int idx)
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012144{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012145 unsigned long val;
12146
12147 if (!nid)
12148 return 0;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012149 if (nid == 0x16)
12150 val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
12151 else
12152 val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
Takashi Iwai033688a2010-09-08 15:47:09 +020012153 return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012154}
12155
Kailang Yangdf694da2005-12-05 19:42:22 +010012156/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012157static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
12158 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010012159{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012160 const char *pfx;
12161 int vbits;
Takashi Iwai033688a2010-09-08 15:47:09 +020012162 int i, err;
Kailang Yangdf694da2005-12-05 19:42:22 +010012163
12164 spec->multiout.num_dacs = 1; /* only use one dac */
12165 spec->multiout.dac_nids = spec->private_dac_nids;
12166 spec->multiout.dac_nids[0] = 2;
12167
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010012168 pfx = alc_get_line_out_pfx(cfg, true);
12169 if (!pfx)
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012170 pfx = "Front";
Takashi Iwai033688a2010-09-08 15:47:09 +020012171 for (i = 0; i < 2; i++) {
12172 err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[i], pfx, i);
12173 if (err < 0)
12174 return err;
12175 if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
12176 err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[i],
12177 "Speaker", i);
12178 if (err < 0)
12179 return err;
12180 }
12181 if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
12182 err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[i],
12183 "Headphone", i);
12184 if (err < 0)
12185 return err;
12186 }
12187 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012188
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012189 vbits = alc262_check_volbit(cfg->line_out_pins[0]) |
12190 alc262_check_volbit(cfg->speaker_pins[0]) |
12191 alc262_check_volbit(cfg->hp_pins[0]);
12192 if (vbits == 1 || vbits == 2)
12193 pfx = "Master"; /* only one mixer is used */
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012194 vbits = 0;
Takashi Iwai033688a2010-09-08 15:47:09 +020012195 for (i = 0; i < 2; i++) {
12196 err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[i], pfx,
12197 &vbits, i);
12198 if (err < 0)
12199 return err;
12200 if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
12201 err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[i],
12202 "Speaker", &vbits, i);
12203 if (err < 0)
12204 return err;
12205 }
12206 if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
12207 err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[i],
12208 "Headphone", &vbits, i);
12209 if (err < 0)
12210 return err;
12211 }
12212 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012213 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +010012214}
12215
Takashi Iwai05f5f472009-08-25 13:10:18 +020012216#define alc262_auto_create_input_ctls \
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +010012217 alc882_auto_create_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +010012218
12219/*
12220 * generic initialization of ADC, input mixers and output mixers
12221 */
12222static struct hda_verb alc262_volume_init_verbs[] = {
12223 /*
12224 * Unmute ADC0-2 and set the default input to mic-in
12225 */
12226 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
12227 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12228 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12229 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12230 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12231 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12232
Takashi Iwaicb53c622007-08-10 17:21:45 +020012233 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010012234 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012235 * Note: PASD motherboards uses the Line In 2 as the input for
12236 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010012237 */
12238 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012239 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12240 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12241 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12242 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12243 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012244
12245 /*
12246 * Set up output mixers (0x0c - 0x0f)
12247 */
12248 /* set vol=0 to output mixers */
12249 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12250 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12251 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yangea1fb292008-08-26 12:58:38 +020012252
Kailang Yangdf694da2005-12-05 19:42:22 +010012253 /* set up input amps for analog loopback */
12254 /* Amp Indices: DAC = 0, mixer = 1 */
12255 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12256 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12257 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12258 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12259 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12260 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12261
12262 /* FIXME: use matrix-type input source selection */
12263 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
12264 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
12265 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12266 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12267 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12268 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12269 /* Input mixer2 */
12270 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12271 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12272 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12273 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12274 /* Input mixer3 */
12275 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12276 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12277 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12278 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12279
12280 { }
12281};
12282
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012283static struct hda_verb alc262_HP_BPC_init_verbs[] = {
12284 /*
12285 * Unmute ADC0-2 and set the default input to mic-in
12286 */
12287 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
12288 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12289 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12290 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12291 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12292 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12293
Takashi Iwaicb53c622007-08-10 17:21:45 +020012294 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012295 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012296 * Note: PASD motherboards uses the Line In 2 as the input for
12297 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012298 */
12299 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012300 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12301 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12302 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12303 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12304 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12305 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12306 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012307
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012308 /*
12309 * Set up output mixers (0x0c - 0x0e)
12310 */
12311 /* set vol=0 to output mixers */
12312 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12313 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12314 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12315
12316 /* set up input amps for analog loopback */
12317 /* Amp Indices: DAC = 0, mixer = 1 */
12318 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12319 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12320 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12321 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12322 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12323 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12324
Takashi Iwaice875f02008-01-28 18:17:43 +010012325 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012326 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12327 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12328
12329 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12330 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12331
12332 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12333 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12334
12335 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12336 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12337 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12338 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12339 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12340
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012341 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012342 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12343 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012344 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012345 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12346 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12347
12348
12349 /* FIXME: use matrix-type input source selection */
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012350 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */
12351 /* Input mixer1: only unmute Mic */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012352 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012353 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12354 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12355 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12356 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12357 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12358 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12359 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12360 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012361 /* Input mixer2 */
12362 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012363 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12364 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12365 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12366 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12367 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12368 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12369 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12370 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012371 /* Input mixer3 */
12372 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012373 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12374 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12375 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12376 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12377 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12378 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12379 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12380 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012381
Takashi Iwaice875f02008-01-28 18:17:43 +010012382 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12383
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012384 { }
12385};
12386
Kailang Yangcd7509a2007-01-26 18:33:17 +010012387static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
12388 /*
12389 * Unmute ADC0-2 and set the default input to mic-in
12390 */
12391 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
12392 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12393 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12394 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12395 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12396 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12397
Takashi Iwaicb53c622007-08-10 17:21:45 +020012398 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +010012399 * mixer widget
12400 * Note: PASD motherboards uses the Line In 2 as the input for front
12401 * panel mic (mic 2)
12402 */
12403 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012404 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12405 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12406 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12407 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12408 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12409 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12410 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
12411 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +010012412 /*
12413 * Set up output mixers (0x0c - 0x0e)
12414 */
12415 /* set vol=0 to output mixers */
12416 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12417 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12418 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12419
12420 /* set up input amps for analog loopback */
12421 /* Amp Indices: DAC = 0, mixer = 1 */
12422 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12423 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12424 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12425 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12426 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12427 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12428
12429
12430 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
12431 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
12432 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
12433 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
12434 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
12435 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
12436 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
12437
12438 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12439 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12440
12441 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12442 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12443
12444 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
12445 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12446 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12447 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
12448 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12449 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12450
12451 /* FIXME: use matrix-type input source selection */
12452 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
12453 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
12454 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
12455 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
12456 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
12457 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
12458 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
12459 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12460 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
12461 /* Input mixer2 */
12462 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12463 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
12464 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
12465 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
12466 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
12467 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12468 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
12469 /* Input mixer3 */
12470 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12471 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
12472 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
12473 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
12474 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
12475 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12476 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
12477
Takashi Iwaice875f02008-01-28 18:17:43 +010012478 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12479
Kailang Yangcd7509a2007-01-26 18:33:17 +010012480 { }
12481};
12482
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012483static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
12484
12485 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */
12486 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12487 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
12488
12489 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */
12490 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
12491 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
12492 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
12493
12494 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */
12495 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12496 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12497 {}
12498};
12499
Takashi Iwai18675e42010-09-08 15:55:44 +020012500/*
12501 * Pin config fixes
12502 */
12503enum {
12504 PINFIX_FSC_H270,
12505};
12506
12507static const struct alc_fixup alc262_fixups[] = {
12508 [PINFIX_FSC_H270] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010012509 .type = ALC_FIXUP_PINS,
12510 .v.pins = (const struct alc_pincfg[]) {
Takashi Iwai18675e42010-09-08 15:55:44 +020012511 { 0x14, 0x99130110 }, /* speaker */
12512 { 0x15, 0x0221142f }, /* front HP */
12513 { 0x1b, 0x0121141f }, /* rear HP */
12514 { }
12515 }
12516 },
Takashi Iwai18675e42010-09-08 15:55:44 +020012517};
12518
12519static struct snd_pci_quirk alc262_fixup_tbl[] = {
12520 SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270),
12521 {}
12522};
12523
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012524
Takashi Iwaicb53c622007-08-10 17:21:45 +020012525#ifdef CONFIG_SND_HDA_POWER_SAVE
12526#define alc262_loopbacks alc880_loopbacks
12527#endif
12528
Sasha Alexandrdef319f2009-06-16 16:00:15 -040012529/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012530#define alc262_pcm_analog_playback alc880_pcm_analog_playback
12531#define alc262_pcm_analog_capture alc880_pcm_analog_capture
12532#define alc262_pcm_digital_playback alc880_pcm_digital_playback
12533#define alc262_pcm_digital_capture alc880_pcm_digital_capture
12534
12535/*
12536 * BIOS auto configuration
12537 */
12538static int alc262_parse_auto_config(struct hda_codec *codec)
12539{
12540 struct alc_spec *spec = codec->spec;
12541 int err;
12542 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
12543
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012544 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12545 alc262_ignore);
12546 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012547 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012548 if (!spec->autocfg.line_outs) {
Takashi Iwai0852d7a2009-02-11 11:35:15 +010012549 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012550 spec->multiout.max_channels = 2;
12551 spec->no_analog = 1;
12552 goto dig_only;
12553 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012554 return 0; /* can't find valid BIOS pin config */
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012555 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012556 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
12557 if (err < 0)
12558 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020012559 err = alc262_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012560 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012561 return err;
12562
12563 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12564
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012565 dig_only:
Takashi Iwai757899a2010-07-30 10:48:14 +020012566 alc_auto_parse_digital(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012567
Takashi Iwai603c4012008-07-30 15:01:44 +020012568 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012569 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010012570
Takashi Iwaid88897e2008-10-31 15:01:37 +010012571 add_verb(spec, alc262_volume_init_verbs);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020012572 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020012573 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010012574
Takashi Iwai776e1842007-08-29 15:07:11 +020012575 err = alc_auto_add_mic_boost(codec);
12576 if (err < 0)
12577 return err;
12578
Kailang Yang6227cdc2010-02-25 08:36:52 +010012579 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020012580
Kailang Yangdf694da2005-12-05 19:42:22 +010012581 return 1;
12582}
12583
12584#define alc262_auto_init_multi_out alc882_auto_init_multi_out
12585#define alc262_auto_init_hp_out alc882_auto_init_hp_out
12586#define alc262_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaif511b012008-08-15 16:46:42 +020012587#define alc262_auto_init_input_src alc882_auto_init_input_src
Kailang Yangdf694da2005-12-05 19:42:22 +010012588
12589
12590/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012591static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010012592{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012593 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010012594 alc262_auto_init_multi_out(codec);
12595 alc262_auto_init_hp_out(codec);
12596 alc262_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020012597 alc262_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020012598 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012599 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020012600 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012601}
12602
12603/*
12604 * configuration and preset
12605 */
Takashi Iwaiea734962011-01-17 11:29:34 +010012606static const char * const alc262_models[ALC262_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012607 [ALC262_BASIC] = "basic",
12608 [ALC262_HIPPO] = "hippo",
12609 [ALC262_HIPPO_1] = "hippo_1",
12610 [ALC262_FUJITSU] = "fujitsu",
12611 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +010012612 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +010012613 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +010012614 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012615 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +020012616 [ALC262_BENQ_T31] = "benq-t31",
12617 [ALC262_SONY_ASSAMD] = "sony-assamd",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020012618 [ALC262_TOSHIBA_S06] = "toshiba-s06",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012619 [ALC262_TOSHIBA_RX1] = "toshiba-rx1",
Tobin Davisf651b502007-10-26 12:40:47 +020012620 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +010012621 [ALC262_LENOVO_3000] = "lenovo-3000",
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012622 [ALC262_NEC] = "nec",
Tony Vroonba340e82009-02-02 19:01:30 +000012623 [ALC262_TYAN] = "tyan",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012624 [ALC262_AUTO] = "auto",
12625};
12626
12627static struct snd_pci_quirk alc262_cfg_tbl[] = {
12628 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012629 SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
Takashi Iwaidea0a502009-02-09 17:14:52 +010012630 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
12631 ALC262_HP_BPC),
12632 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series",
12633 ALC262_HP_BPC),
Takashi Iwai5734a072011-01-19 17:07:12 +010012634 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1500, "HP z series",
12635 ALC262_HP_BPC),
Takashi Iwai53eff7e2009-02-27 17:49:44 +010012636 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
12637 ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012638 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012639 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012640 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012641 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012642 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012643 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012644 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012645 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012646 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
12647 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
12648 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012649 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
12650 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +010012651 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012652 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012653 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012654 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaibd6afe32009-03-04 11:30:25 +010012655 SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */
Takashi Iwai376b5082009-06-22 11:03:13 +020012656 SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06),
Daniel T Chen95491d92009-11-08 19:03:55 -050012657 SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO),
Takashi Iwai12929ba2009-11-17 15:58:35 +010012658 SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO),
Takashi Iwaic5b51652009-11-17 16:01:58 +010012659#if 0 /* disable the quirk since model=auto works better in recent versions */
Takashi Iwaif872a912009-02-26 00:57:01 +010012660 SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
12661 ALC262_SONY_ASSAMD),
Takashi Iwaic5b51652009-11-17 16:01:58 +010012662#endif
Akio Idehara36ca6e12008-06-09 22:57:40 +090012663 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012664 ALC262_TOSHIBA_RX1),
Kailang Yang80ffe862008-10-15 11:23:27 +020012665 SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012666 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +010012667 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Tony Vroonba340e82009-02-02 19:01:30 +000012668 SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
Takashi Iwaidea0a502009-02-09 17:14:52 +010012669 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1",
12670 ALC262_ULTRA),
Luke Yelavich3e420e72008-12-16 12:37:47 +110012671 SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
Jiang zhe0e31daf2008-03-20 12:12:39 +010012672 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012673 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +020012674 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012675 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +010012676 {}
12677};
12678
12679static struct alc_config_preset alc262_presets[] = {
12680 [ALC262_BASIC] = {
12681 .mixers = { alc262_base_mixer },
12682 .init_verbs = { alc262_init_verbs },
12683 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12684 .dac_nids = alc262_dac_nids,
12685 .hp_nid = 0x03,
12686 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12687 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +010012688 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +010012689 },
Kailang Yangccc656c2006-10-17 12:32:26 +020012690 [ALC262_HIPPO] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020012691 .mixers = { alc262_hippo_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020012692 .init_verbs = { alc262_init_verbs, alc_hp15_unsol_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020012693 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12694 .dac_nids = alc262_dac_nids,
12695 .hp_nid = 0x03,
12696 .dig_out_nid = ALC262_DIGOUT_NID,
12697 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12698 .channel_mode = alc262_modes,
12699 .input_mux = &alc262_capture_source,
12700 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012701 .setup = alc262_hippo_setup,
12702 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020012703 },
12704 [ALC262_HIPPO_1] = {
12705 .mixers = { alc262_hippo1_mixer },
12706 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
12707 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12708 .dac_nids = alc262_dac_nids,
12709 .hp_nid = 0x02,
12710 .dig_out_nid = ALC262_DIGOUT_NID,
12711 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12712 .channel_mode = alc262_modes,
12713 .input_mux = &alc262_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020012714 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012715 .setup = alc262_hippo1_setup,
12716 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020012717 },
Takashi Iwai834be882006-03-01 14:16:17 +010012718 [ALC262_FUJITSU] = {
12719 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020012720 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
12721 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +010012722 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12723 .dac_nids = alc262_dac_nids,
12724 .hp_nid = 0x03,
12725 .dig_out_nid = ALC262_DIGOUT_NID,
12726 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12727 .channel_mode = alc262_modes,
12728 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012729 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwaiebc7a402008-05-20 09:23:05 +020012730 .init_hook = alc262_fujitsu_init_hook,
Takashi Iwai834be882006-03-01 14:16:17 +010012731 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012732 [ALC262_HP_BPC] = {
12733 .mixers = { alc262_HP_BPC_mixer },
12734 .init_verbs = { alc262_HP_BPC_init_verbs },
12735 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12736 .dac_nids = alc262_dac_nids,
12737 .hp_nid = 0x03,
12738 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12739 .channel_mode = alc262_modes,
12740 .input_mux = &alc262_HP_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010012741 .unsol_event = alc262_hp_bpc_unsol_event,
12742 .init_hook = alc262_hp_bpc_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012743 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010012744 [ALC262_HP_BPC_D7000_WF] = {
12745 .mixers = { alc262_HP_BPC_WildWest_mixer },
12746 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
12747 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12748 .dac_nids = alc262_dac_nids,
12749 .hp_nid = 0x03,
12750 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12751 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020012752 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010012753 .unsol_event = alc262_hp_wildwest_unsol_event,
12754 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012755 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010012756 [ALC262_HP_BPC_D7000_WL] = {
12757 .mixers = { alc262_HP_BPC_WildWest_mixer,
12758 alc262_HP_BPC_WildWest_option_mixer },
12759 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
12760 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12761 .dac_nids = alc262_dac_nids,
12762 .hp_nid = 0x03,
12763 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12764 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020012765 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010012766 .unsol_event = alc262_hp_wildwest_unsol_event,
12767 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012768 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012769 [ALC262_HP_TC_T5735] = {
12770 .mixers = { alc262_hp_t5735_mixer },
12771 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
12772 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12773 .dac_nids = alc262_dac_nids,
12774 .hp_nid = 0x03,
12775 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12776 .channel_mode = alc262_modes,
12777 .input_mux = &alc262_capture_source,
Takashi Iwaidc99be42010-01-20 08:35:06 +010012778 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012779 .setup = alc262_hp_t5735_setup,
Takashi Iwaidc99be42010-01-20 08:35:06 +010012780 .init_hook = alc_inithook,
Kailang Yang8c427222008-01-10 13:03:59 +010012781 },
12782 [ALC262_HP_RP5700] = {
12783 .mixers = { alc262_hp_rp5700_mixer },
12784 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
12785 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12786 .dac_nids = alc262_dac_nids,
12787 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12788 .channel_mode = alc262_modes,
12789 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012790 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +020012791 [ALC262_BENQ_ED8] = {
12792 .mixers = { alc262_base_mixer },
12793 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
12794 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12795 .dac_nids = alc262_dac_nids,
12796 .hp_nid = 0x03,
12797 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12798 .channel_mode = alc262_modes,
12799 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012800 },
Kailang Yang272a5272007-05-14 11:00:38 +020012801 [ALC262_SONY_ASSAMD] = {
12802 .mixers = { alc262_sony_mixer },
12803 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
12804 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12805 .dac_nids = alc262_dac_nids,
12806 .hp_nid = 0x02,
12807 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12808 .channel_mode = alc262_modes,
12809 .input_mux = &alc262_capture_source,
12810 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012811 .setup = alc262_hippo_setup,
12812 .init_hook = alc262_hippo_automute,
Kailang Yang83c34212007-07-05 11:43:05 +020012813 },
12814 [ALC262_BENQ_T31] = {
12815 .mixers = { alc262_benq_t31_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020012816 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs,
12817 alc_hp15_unsol_verbs },
Kailang Yang83c34212007-07-05 11:43:05 +020012818 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12819 .dac_nids = alc262_dac_nids,
12820 .hp_nid = 0x03,
12821 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12822 .channel_mode = alc262_modes,
12823 .input_mux = &alc262_capture_source,
12824 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012825 .setup = alc262_hippo_setup,
12826 .init_hook = alc262_hippo_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020012827 },
Tobin Davisf651b502007-10-26 12:40:47 +020012828 [ALC262_ULTRA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012829 .mixers = { alc262_ultra_mixer },
12830 .cap_mixer = alc262_ultra_capture_mixer,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012831 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +020012832 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12833 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +020012834 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12835 .channel_mode = alc262_modes,
12836 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012837 .adc_nids = alc262_adc_nids, /* ADC0 */
12838 .capsrc_nids = alc262_capsrc_nids,
12839 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +020012840 .unsol_event = alc262_ultra_unsol_event,
12841 .init_hook = alc262_ultra_automute,
12842 },
Jiang zhe0e31daf2008-03-20 12:12:39 +010012843 [ALC262_LENOVO_3000] = {
12844 .mixers = { alc262_lenovo_3000_mixer },
12845 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
Daniel T Chene2595322009-12-19 18:19:02 -050012846 alc262_lenovo_3000_unsol_verbs,
12847 alc262_lenovo_3000_init_verbs },
Jiang zhe0e31daf2008-03-20 12:12:39 +010012848 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12849 .dac_nids = alc262_dac_nids,
12850 .hp_nid = 0x03,
12851 .dig_out_nid = ALC262_DIGOUT_NID,
12852 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12853 .channel_mode = alc262_modes,
12854 .input_mux = &alc262_fujitsu_capture_source,
12855 .unsol_event = alc262_lenovo_3000_unsol_event,
12856 },
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012857 [ALC262_NEC] = {
12858 .mixers = { alc262_nec_mixer },
12859 .init_verbs = { alc262_nec_verbs },
12860 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12861 .dac_nids = alc262_dac_nids,
12862 .hp_nid = 0x03,
12863 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12864 .channel_mode = alc262_modes,
12865 .input_mux = &alc262_capture_source,
12866 },
Kailang Yang4e555fe2008-08-26 13:05:55 +020012867 [ALC262_TOSHIBA_S06] = {
12868 .mixers = { alc262_toshiba_s06_mixer },
12869 .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
12870 alc262_eapd_verbs },
12871 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12872 .capsrc_nids = alc262_dmic_capsrc_nids,
12873 .dac_nids = alc262_dac_nids,
12874 .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
Takashi Iwaiae14ef62009-06-22 08:16:56 +020012875 .num_adc_nids = 1, /* single ADC */
Kailang Yang4e555fe2008-08-26 13:05:55 +020012876 .dig_out_nid = ALC262_DIGOUT_NID,
12877 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12878 .channel_mode = alc262_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012879 .unsol_event = alc_sku_unsol_event,
12880 .setup = alc262_toshiba_s06_setup,
12881 .init_hook = alc_inithook,
Kailang Yang4e555fe2008-08-26 13:05:55 +020012882 },
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012883 [ALC262_TOSHIBA_RX1] = {
12884 .mixers = { alc262_toshiba_rx1_mixer },
12885 .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
12886 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12887 .dac_nids = alc262_dac_nids,
12888 .hp_nid = 0x03,
12889 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12890 .channel_mode = alc262_modes,
12891 .input_mux = &alc262_capture_source,
12892 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012893 .setup = alc262_hippo_setup,
12894 .init_hook = alc262_hippo_automute,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012895 },
Tony Vroonba340e82009-02-02 19:01:30 +000012896 [ALC262_TYAN] = {
12897 .mixers = { alc262_tyan_mixer },
12898 .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
12899 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12900 .dac_nids = alc262_dac_nids,
12901 .hp_nid = 0x02,
12902 .dig_out_nid = ALC262_DIGOUT_NID,
12903 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12904 .channel_mode = alc262_modes,
12905 .input_mux = &alc262_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012906 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012907 .setup = alc262_tyan_setup,
12908 .init_hook = alc_automute_amp,
Tony Vroonba340e82009-02-02 19:01:30 +000012909 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012910};
12911
12912static int patch_alc262(struct hda_codec *codec)
12913{
12914 struct alc_spec *spec;
12915 int board_config;
12916 int err;
12917
Robert P. J. Daydc041e02006-12-19 14:44:15 +010012918 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010012919 if (spec == NULL)
12920 return -ENOMEM;
12921
12922 codec->spec = spec;
12923#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012924 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
12925 * under-run
12926 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012927 {
12928 int tmp;
12929 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
12930 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
12931 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
12932 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
12933 }
12934#endif
Kailang Yangda00c242010-03-19 11:23:45 +010012935 alc_auto_parse_customize_define(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012936
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020012937 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
12938
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012939 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
12940 alc262_models,
12941 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +010012942
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012943 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020012944 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
12945 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010012946 board_config = ALC262_AUTO;
12947 }
12948
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010012949 if (board_config == ALC262_AUTO) {
12950 alc_pick_fixup(codec, NULL, alc262_fixup_tbl, alc262_fixups);
12951 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
12952 }
Takashi Iwai18675e42010-09-08 15:55:44 +020012953
Kailang Yangdf694da2005-12-05 19:42:22 +010012954 if (board_config == ALC262_AUTO) {
12955 /* automatic parse from the BIOS config */
12956 err = alc262_parse_auto_config(codec);
12957 if (err < 0) {
12958 alc_free(codec);
12959 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012960 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012961 printk(KERN_INFO
12962 "hda_codec: Cannot set up configuration "
12963 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010012964 board_config = ALC262_BASIC;
12965 }
12966 }
12967
Takashi Iwaidc1eae22010-07-29 15:30:02 +020012968 if (!spec->no_analog && has_cdefine_beep(codec)) {
Takashi Iwai07eba612009-02-19 08:06:35 +010012969 err = snd_hda_attach_beep_device(codec, 0x1);
12970 if (err < 0) {
12971 alc_free(codec);
12972 return err;
12973 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090012974 }
12975
Kailang Yangdf694da2005-12-05 19:42:22 +010012976 if (board_config != ALC262_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020012977 setup_preset(codec, &alc262_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010012978
Kailang Yangdf694da2005-12-05 19:42:22 +010012979 spec->stream_analog_playback = &alc262_pcm_analog_playback;
12980 spec->stream_analog_capture = &alc262_pcm_analog_capture;
Kailang Yangea1fb292008-08-26 12:58:38 +020012981
Kailang Yangdf694da2005-12-05 19:42:22 +010012982 spec->stream_digital_playback = &alc262_pcm_digital_playback;
12983 spec->stream_digital_capture = &alc262_pcm_digital_capture;
12984
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012985 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwai8c927b42009-06-22 10:56:54 +020012986 int i;
12987 /* check whether the digital-mic has to be supported */
12988 for (i = 0; i < spec->input_mux->num_items; i++) {
12989 if (spec->input_mux->items[i].index >= 9)
12990 break;
12991 }
12992 if (i < spec->input_mux->num_items) {
12993 /* use only ADC0 */
12994 spec->adc_nids = alc262_dmic_adc_nids;
12995 spec->num_adc_nids = 1;
12996 spec->capsrc_nids = alc262_dmic_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +010012997 } else {
Takashi Iwai8c927b42009-06-22 10:56:54 +020012998 /* all analog inputs */
12999 /* check whether NID 0x07 is valid */
13000 unsigned int wcap = get_wcaps(codec, 0x07);
13001
13002 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020013003 wcap = get_wcaps_type(wcap);
Takashi Iwai8c927b42009-06-22 10:56:54 +020013004 if (wcap != AC_WID_AUD_IN) {
13005 spec->adc_nids = alc262_adc_nids_alt;
13006 spec->num_adc_nids =
13007 ARRAY_SIZE(alc262_adc_nids_alt);
13008 spec->capsrc_nids = alc262_capsrc_nids_alt;
13009 } else {
13010 spec->adc_nids = alc262_adc_nids;
13011 spec->num_adc_nids =
13012 ARRAY_SIZE(alc262_adc_nids);
13013 spec->capsrc_nids = alc262_capsrc_nids;
13014 }
Kailang Yangdf694da2005-12-05 19:42:22 +010013015 }
13016 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +010013017 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020013018 set_capture_mixer(codec);
Takashi Iwaidc1eae22010-07-29 15:30:02 +020013019 if (!spec->no_analog && has_cdefine_beep(codec))
Takashi Iwai07eba612009-02-19 08:06:35 +010013020 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Kailang Yangdf694da2005-12-05 19:42:22 +010013021
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010013022 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwai18675e42010-09-08 15:55:44 +020013023
Takashi Iwai2134ea42008-01-10 16:53:55 +010013024 spec->vmaster_nid = 0x0c;
13025
Kailang Yangdf694da2005-12-05 19:42:22 +010013026 codec->patch_ops = alc_patch_ops;
13027 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010013028 spec->init_hook = alc262_auto_init;
Kailang Yangbf1b0222010-10-21 08:49:56 +020013029
13030 alc_init_jacks(codec);
Takashi Iwaicb53c622007-08-10 17:21:45 +020013031#ifdef CONFIG_SND_HDA_POWER_SAVE
13032 if (!spec->loopback.amplist)
13033 spec->loopback.amplist = alc262_loopbacks;
13034#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020013035
Kailang Yangdf694da2005-12-05 19:42:22 +010013036 return 0;
13037}
13038
Kailang Yangdf694da2005-12-05 19:42:22 +010013039/*
Kailang Yanga361d842007-06-05 12:30:55 +020013040 * ALC268 channel source setting (2 channel)
13041 */
13042#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
13043#define alc268_modes alc260_modes
Kailang Yangea1fb292008-08-26 12:58:38 +020013044
Kailang Yanga361d842007-06-05 12:30:55 +020013045static hda_nid_t alc268_dac_nids[2] = {
13046 /* front, hp */
13047 0x02, 0x03
13048};
13049
13050static hda_nid_t alc268_adc_nids[2] = {
13051 /* ADC0-1 */
13052 0x08, 0x07
13053};
13054
13055static hda_nid_t alc268_adc_nids_alt[1] = {
13056 /* ADC0 */
13057 0x08
13058};
13059
Takashi Iwaie1406342008-02-11 18:32:32 +010013060static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
13061
Kailang Yanga361d842007-06-05 12:30:55 +020013062static struct snd_kcontrol_new alc268_base_mixer[] = {
13063 /* output mixer control */
13064 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
13065 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13066 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
13067 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013068 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13069 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
13070 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +020013071 { }
13072};
13073
Takashi Iwai42171c12009-05-08 14:11:43 +020013074static struct snd_kcontrol_new alc268_toshiba_mixer[] = {
13075 /* output mixer control */
13076 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
13077 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
13078 ALC262_HIPPO_MASTER_SWITCH,
David Henningsson5f99f862011-01-04 15:24:24 +010013079 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13080 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
13081 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020013082 { }
13083};
13084
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013085/* bind Beep switches of both NID 0x0f and 0x10 */
13086static struct hda_bind_ctls alc268_bind_beep_sw = {
13087 .ops = &snd_hda_bind_sw,
13088 .values = {
13089 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
13090 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
13091 0
13092 },
13093};
13094
13095static struct snd_kcontrol_new alc268_beep_mixer[] = {
13096 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
13097 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
13098 { }
13099};
13100
Kailang Yangd1a991a2007-08-15 16:21:59 +020013101static struct hda_verb alc268_eapd_verbs[] = {
13102 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
13103 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
13104 { }
13105};
13106
Takashi Iwaid2738092007-08-16 14:59:45 +020013107/* Toshiba specific */
Takashi Iwaid2738092007-08-16 14:59:45 +020013108static struct hda_verb alc268_toshiba_verbs[] = {
13109 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13110 { } /* end */
13111};
13112
13113/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +020013114/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +020013115static struct hda_bind_ctls alc268_acer_bind_master_vol = {
13116 .ops = &snd_hda_bind_vol,
13117 .values = {
13118 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
13119 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
13120 0
13121 },
13122};
13123
Takashi Iwai889c4392007-08-23 18:56:52 +020013124/* mute/unmute internal speaker according to the hp jack and mute state */
13125static void alc268_acer_automute(struct hda_codec *codec, int force)
13126{
13127 struct alc_spec *spec = codec->spec;
13128 unsigned int mute;
13129
13130 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080013131 spec->jack_present = snd_hda_jack_detect(codec, 0x14);
Takashi Iwai889c4392007-08-23 18:56:52 +020013132 spec->sense_updated = 1;
13133 }
13134 if (spec->jack_present)
13135 mute = HDA_AMP_MUTE; /* mute internal speaker */
13136 else /* unmute internal speaker if necessary */
13137 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
13138 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
13139 HDA_AMP_MUTE, mute);
13140}
13141
13142
13143/* bind hp and internal speaker mute (with plug check) */
13144static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
13145 struct snd_ctl_elem_value *ucontrol)
13146{
13147 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
13148 long *valp = ucontrol->value.integer.value;
13149 int change;
13150
Takashi Iwai8de56b72009-07-24 16:51:47 +020013151 change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
Takashi Iwai889c4392007-08-23 18:56:52 +020013152 if (change)
13153 alc268_acer_automute(codec, 0);
13154 return change;
13155}
Takashi Iwaid2738092007-08-16 14:59:45 +020013156
Kailang Yang8ef355d2008-08-26 13:10:22 +020013157static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
13158 /* output mixer control */
13159 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13160 {
13161 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13162 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013163 .subdevice = HDA_SUBDEV_AMP_FLAG,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013164 .info = snd_hda_mixer_amp_switch_info,
13165 .get = snd_hda_mixer_amp_switch_get,
13166 .put = alc268_acer_master_sw_put,
13167 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13168 },
13169 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
13170 { }
13171};
13172
Takashi Iwaid2738092007-08-16 14:59:45 +020013173static struct snd_kcontrol_new alc268_acer_mixer[] = {
13174 /* output mixer control */
13175 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13176 {
13177 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13178 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013179 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwaid2738092007-08-16 14:59:45 +020013180 .info = snd_hda_mixer_amp_switch_info,
13181 .get = snd_hda_mixer_amp_switch_get,
13182 .put = alc268_acer_master_sw_put,
13183 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13184 },
David Henningsson5f99f862011-01-04 15:24:24 +010013185 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13186 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
13187 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +020013188 { }
13189};
13190
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013191static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
13192 /* output mixer control */
13193 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13194 {
13195 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13196 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013197 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013198 .info = snd_hda_mixer_amp_switch_info,
13199 .get = snd_hda_mixer_amp_switch_get,
13200 .put = alc268_acer_master_sw_put,
13201 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13202 },
David Henningsson5f99f862011-01-04 15:24:24 +010013203 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13204 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013205 { }
13206};
13207
Kailang Yang8ef355d2008-08-26 13:10:22 +020013208static struct hda_verb alc268_acer_aspire_one_verbs[] = {
13209 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13210 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13211 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13212 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13213 {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
13214 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
13215 { }
13216};
13217
Takashi Iwaid2738092007-08-16 14:59:45 +020013218static struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013219 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
13220 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +020013221 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13222 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013223 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13224 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +020013225 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13226 { }
13227};
13228
13229/* unsolicited event for HP jack sensing */
Takashi Iwai42171c12009-05-08 14:11:43 +020013230#define alc268_toshiba_unsol_event alc262_hippo_unsol_event
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013231#define alc268_toshiba_setup alc262_hippo_setup
13232#define alc268_toshiba_automute alc262_hippo_automute
Takashi Iwaid2738092007-08-16 14:59:45 +020013233
13234static void alc268_acer_unsol_event(struct hda_codec *codec,
13235 unsigned int res)
13236{
Takashi Iwai889c4392007-08-23 18:56:52 +020013237 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020013238 return;
13239 alc268_acer_automute(codec, 1);
13240}
13241
Takashi Iwai889c4392007-08-23 18:56:52 +020013242static void alc268_acer_init_hook(struct hda_codec *codec)
13243{
13244 alc268_acer_automute(codec, 1);
13245}
13246
Kailang Yang8ef355d2008-08-26 13:10:22 +020013247/* toggle speaker-output according to the hp-jack state */
13248static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
13249{
13250 unsigned int present;
13251 unsigned char bits;
13252
Wu Fengguang864f92b2009-11-18 12:38:02 +080013253 present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013254 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang8ef355d2008-08-26 13:10:22 +020013255 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013256 HDA_AMP_MUTE, bits);
Kailang Yang8ef355d2008-08-26 13:10:22 +020013257 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013258 HDA_AMP_MUTE, bits);
Kailang Yang8ef355d2008-08-26 13:10:22 +020013259}
13260
Kailang Yang8ef355d2008-08-26 13:10:22 +020013261static void alc268_acer_lc_unsol_event(struct hda_codec *codec,
13262 unsigned int res)
13263{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013264 switch (res >> 26) {
13265 case ALC880_HP_EVENT:
Kailang Yang8ef355d2008-08-26 13:10:22 +020013266 alc268_aspire_one_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013267 break;
13268 case ALC880_MIC_EVENT:
13269 alc_mic_automute(codec);
13270 break;
13271 }
13272}
13273
13274static void alc268_acer_lc_setup(struct hda_codec *codec)
13275{
13276 struct alc_spec *spec = codec->spec;
13277 spec->ext_mic.pin = 0x18;
13278 spec->ext_mic.mux_idx = 0;
13279 spec->int_mic.pin = 0x12;
13280 spec->int_mic.mux_idx = 6;
13281 spec->auto_mic = 1;
Kailang Yang8ef355d2008-08-26 13:10:22 +020013282}
13283
13284static void alc268_acer_lc_init_hook(struct hda_codec *codec)
13285{
13286 alc268_aspire_one_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013287 alc_mic_automute(codec);
Kailang Yang8ef355d2008-08-26 13:10:22 +020013288}
13289
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013290static struct snd_kcontrol_new alc268_dell_mixer[] = {
13291 /* output mixer control */
13292 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13293 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13294 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13295 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013296 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13297 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013298 { }
13299};
13300
13301static struct hda_verb alc268_dell_verbs[] = {
13302 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13303 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13304 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013305 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013306 { }
13307};
13308
13309/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013310static void alc268_dell_setup(struct hda_codec *codec)
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013311{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013312 struct alc_spec *spec = codec->spec;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013313
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013314 spec->autocfg.hp_pins[0] = 0x15;
13315 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013316 spec->ext_mic.pin = 0x18;
13317 spec->ext_mic.mux_idx = 0;
13318 spec->int_mic.pin = 0x19;
13319 spec->int_mic.mux_idx = 1;
13320 spec->auto_mic = 1;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013321}
13322
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013323static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
13324 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
13325 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13326 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
13327 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
13328 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13329 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013330 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13331 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013332 { }
13333};
13334
13335static struct hda_verb alc267_quanta_il1_verbs[] = {
13336 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13337 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
13338 { }
13339};
13340
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013341static void alc267_quanta_il1_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013342{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013343 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013344 spec->autocfg.hp_pins[0] = 0x15;
13345 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013346 spec->ext_mic.pin = 0x18;
13347 spec->ext_mic.mux_idx = 0;
13348 spec->int_mic.pin = 0x19;
13349 spec->int_mic.mux_idx = 1;
13350 spec->auto_mic = 1;
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013351}
13352
Kailang Yanga361d842007-06-05 12:30:55 +020013353/*
13354 * generic initialization of ADC, input mixers and output mixers
13355 */
13356static struct hda_verb alc268_base_init_verbs[] = {
13357 /* Unmute DAC0-1 and set vol = 0 */
13358 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020013359 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020013360
13361 /*
13362 * Set up output mixers (0x0c - 0x0e)
13363 */
13364 /* set vol=0 to output mixers */
13365 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020013366 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
13367
13368 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13369 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13370
13371 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
13372 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
13373 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
13374 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13375 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13376 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13377 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13378 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13379
13380 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13381 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13382 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13383 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013384 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013385
13386 /* set PCBEEP vol = 0, mute connections */
13387 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13388 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13389 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020013390
Jiang Zhea9b3aa82007-12-20 13:13:13 +010013391 /* Unmute Selector 23h,24h and set the default input to mic-in */
Kailang Yangea1fb292008-08-26 12:58:38 +020013392
Jiang Zhea9b3aa82007-12-20 13:13:13 +010013393 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
13394 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13395 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
13396 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013397
Kailang Yanga361d842007-06-05 12:30:55 +020013398 { }
13399};
13400
13401/*
13402 * generic initialization of ADC, input mixers and output mixers
13403 */
13404static struct hda_verb alc268_volume_init_verbs[] = {
13405 /* set output DAC */
Takashi Iwai4cfb91c2009-01-23 12:53:09 +010013406 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13407 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020013408
13409 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13410 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13411 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13412 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13413 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13414
Kailang Yanga361d842007-06-05 12:30:55 +020013415 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020013416 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13417 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13418
13419 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013420 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013421
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013422 /* set PCBEEP vol = 0, mute connections */
13423 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13424 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13425 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020013426
13427 { }
13428};
13429
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013430static struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = {
13431 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13432 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
13433 { } /* end */
13434};
13435
Kailang Yanga361d842007-06-05 12:30:55 +020013436static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
13437 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13438 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013439 _DEFINE_CAPSRC(1),
Kailang Yanga361d842007-06-05 12:30:55 +020013440 { } /* end */
13441};
13442
13443static struct snd_kcontrol_new alc268_capture_mixer[] = {
13444 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13445 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
13446 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
13447 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013448 _DEFINE_CAPSRC(2),
Kailang Yanga361d842007-06-05 12:30:55 +020013449 { } /* end */
13450};
13451
13452static struct hda_input_mux alc268_capture_source = {
13453 .num_items = 4,
13454 .items = {
13455 { "Mic", 0x0 },
13456 { "Front Mic", 0x1 },
13457 { "Line", 0x2 },
13458 { "CD", 0x3 },
13459 },
13460};
13461
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013462static struct hda_input_mux alc268_acer_capture_source = {
13463 .num_items = 3,
13464 .items = {
13465 { "Mic", 0x0 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013466 { "Internal Mic", 0x1 },
13467 { "Line", 0x2 },
13468 },
13469};
13470
13471static struct hda_input_mux alc268_acer_dmic_capture_source = {
13472 .num_items = 3,
13473 .items = {
13474 { "Mic", 0x0 },
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013475 { "Internal Mic", 0x6 },
13476 { "Line", 0x2 },
13477 },
13478};
13479
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013480#ifdef CONFIG_SND_DEBUG
13481static struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013482 /* Volume widgets */
13483 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13484 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13485 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
13486 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
13487 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
13488 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
13489 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
13490 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
13491 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
13492 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
13493 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
13494 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
13495 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010013496 /* The below appears problematic on some hardwares */
13497 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013498 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13499 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
13500 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
13501 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
13502
13503 /* Modes for retasking pin widgets */
13504 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
13505 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
13506 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
13507 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
13508
13509 /* Controls for GPIO pins, assuming they are configured as outputs */
13510 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
13511 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
13512 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
13513 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
13514
13515 /* Switches to allow the digital SPDIF output pin to be enabled.
13516 * The ALC268 does not have an SPDIF input.
13517 */
13518 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
13519
13520 /* A switch allowing EAPD to be enabled. Some laptops seem to use
13521 * this output to turn on an external amplifier.
13522 */
13523 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
13524 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
13525
13526 { } /* end */
13527};
13528#endif
13529
Kailang Yanga361d842007-06-05 12:30:55 +020013530/* create input playback/capture controls for the given pin */
13531static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
13532 const char *ctlname, int idx)
13533{
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013534 hda_nid_t dac;
Kailang Yanga361d842007-06-05 12:30:55 +020013535 int err;
13536
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013537 switch (nid) {
13538 case 0x14:
13539 case 0x16:
13540 dac = 0x02;
13541 break;
13542 case 0x15:
Takashi Iwaib08b1632010-07-30 14:08:25 +020013543 case 0x1a: /* ALC259/269 only */
13544 case 0x1b: /* ALC259/269 only */
Kailang Yang531d8792010-04-09 10:57:33 +020013545 case 0x21: /* ALC269vb has this pin, too */
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013546 dac = 0x03;
13547 break;
13548 default:
Takashi Iwaic7a94342010-07-30 14:10:43 +020013549 snd_printd(KERN_WARNING "hda_codec: "
13550 "ignoring pin 0x%x as unknown\n", nid);
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013551 return 0;
13552 }
13553 if (spec->multiout.dac_nids[0] != dac &&
13554 spec->multiout.dac_nids[1] != dac) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013555 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013556 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
Kailang Yanga361d842007-06-05 12:30:55 +020013557 HDA_OUTPUT));
13558 if (err < 0)
13559 return err;
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013560 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
13561 }
13562
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013563 if (nid != 0x16)
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013564 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Kailang Yanga361d842007-06-05 12:30:55 +020013565 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013566 else /* mono */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013567 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013568 HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013569 if (err < 0)
13570 return err;
13571 return 0;
13572}
13573
13574/* add playback controls from the parsed DAC table */
13575static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
13576 const struct auto_pin_cfg *cfg)
13577{
13578 hda_nid_t nid;
13579 int err;
13580
Kailang Yanga361d842007-06-05 12:30:55 +020013581 spec->multiout.dac_nids = spec->private_dac_nids;
Kailang Yanga361d842007-06-05 12:30:55 +020013582
13583 nid = cfg->line_out_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013584 if (nid) {
13585 const char *name;
13586 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
13587 name = "Speaker";
13588 else
13589 name = "Front";
13590 err = alc268_new_analog_output(spec, nid, name, 0);
13591 if (err < 0)
13592 return err;
13593 }
Kailang Yanga361d842007-06-05 12:30:55 +020013594
13595 nid = cfg->speaker_pins[0];
13596 if (nid == 0x1d) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013597 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Speaker",
Kailang Yanga361d842007-06-05 12:30:55 +020013598 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
13599 if (err < 0)
13600 return err;
David Henningsson7bfb9c02010-08-02 13:13:25 +020013601 } else if (nid) {
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013602 err = alc268_new_analog_output(spec, nid, "Speaker", 0);
13603 if (err < 0)
13604 return err;
Kailang Yanga361d842007-06-05 12:30:55 +020013605 }
13606 nid = cfg->hp_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013607 if (nid) {
13608 err = alc268_new_analog_output(spec, nid, "Headphone", 0);
13609 if (err < 0)
13610 return err;
13611 }
Kailang Yanga361d842007-06-05 12:30:55 +020013612
13613 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
13614 if (nid == 0x16) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013615 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, "Mono",
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013616 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013617 if (err < 0)
13618 return err;
13619 }
Kailang Yangea1fb292008-08-26 12:58:38 +020013620 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020013621}
13622
13623/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020013624static int alc268_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yanga361d842007-06-05 12:30:55 +020013625 const struct auto_pin_cfg *cfg)
13626{
Takashi Iwai05f5f472009-08-25 13:10:18 +020013627 return alc_auto_create_input_ctls(codec, cfg, 0, 0x23, 0x24);
Kailang Yanga361d842007-06-05 12:30:55 +020013628}
13629
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013630static void alc268_auto_set_output_and_unmute(struct hda_codec *codec,
13631 hda_nid_t nid, int pin_type)
13632{
13633 int idx;
13634
13635 alc_set_pin_output(codec, nid, pin_type);
13636 if (nid == 0x14 || nid == 0x16)
13637 idx = 0;
13638 else
13639 idx = 1;
13640 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
13641}
13642
13643static void alc268_auto_init_multi_out(struct hda_codec *codec)
13644{
13645 struct alc_spec *spec = codec->spec;
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013646 int i;
13647
13648 for (i = 0; i < spec->autocfg.line_outs; i++) {
13649 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013650 int pin_type = get_pin_type(spec->autocfg.line_out_type);
13651 alc268_auto_set_output_and_unmute(codec, nid, pin_type);
13652 }
13653}
13654
13655static void alc268_auto_init_hp_out(struct hda_codec *codec)
13656{
13657 struct alc_spec *spec = codec->spec;
13658 hda_nid_t pin;
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013659 int i;
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013660
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013661 for (i = 0; i < spec->autocfg.hp_outs; i++) {
13662 pin = spec->autocfg.hp_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013663 alc268_auto_set_output_and_unmute(codec, pin, PIN_HP);
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013664 }
13665 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
13666 pin = spec->autocfg.speaker_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013667 alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT);
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013668 }
13669 if (spec->autocfg.mono_out_pin)
13670 snd_hda_codec_write(codec, spec->autocfg.mono_out_pin, 0,
13671 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013672}
13673
Kailang Yanga361d842007-06-05 12:30:55 +020013674static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
13675{
13676 struct alc_spec *spec = codec->spec;
13677 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
13678 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
13679 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
13680 unsigned int dac_vol1, dac_vol2;
13681
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013682 if (line_nid == 0x1d || speaker_nid == 0x1d) {
Kailang Yanga361d842007-06-05 12:30:55 +020013683 snd_hda_codec_write(codec, speaker_nid, 0,
13684 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013685 /* mute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013686 snd_hda_codec_write(codec, 0x0f, 0,
13687 AC_VERB_SET_AMP_GAIN_MUTE,
13688 AMP_IN_UNMUTE(1));
13689 snd_hda_codec_write(codec, 0x10, 0,
13690 AC_VERB_SET_AMP_GAIN_MUTE,
13691 AMP_IN_UNMUTE(1));
13692 } else {
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013693 /* unmute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013694 snd_hda_codec_write(codec, 0x0f, 0,
13695 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13696 snd_hda_codec_write(codec, 0x10, 0,
13697 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13698 }
13699
13700 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020013701 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013702 dac_vol2 = AMP_OUT_ZERO;
13703 else if (line_nid == 0x15)
13704 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020013705 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013706 dac_vol2 = AMP_OUT_ZERO;
13707 else if (hp_nid == 0x15)
13708 dac_vol1 = AMP_OUT_ZERO;
13709 if (line_nid != 0x16 || hp_nid != 0x16 ||
13710 spec->autocfg.line_out_pins[1] != 0x16 ||
13711 spec->autocfg.line_out_pins[2] != 0x16)
13712 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
13713
13714 snd_hda_codec_write(codec, 0x02, 0,
13715 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
13716 snd_hda_codec_write(codec, 0x03, 0,
13717 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
13718}
13719
Sasha Alexandrdef319f2009-06-16 16:00:15 -040013720/* pcm configuration: identical with ALC880 */
Kailang Yanga361d842007-06-05 12:30:55 +020013721#define alc268_pcm_analog_playback alc880_pcm_analog_playback
13722#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010013723#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020013724#define alc268_pcm_digital_playback alc880_pcm_digital_playback
13725
13726/*
13727 * BIOS auto configuration
13728 */
13729static int alc268_parse_auto_config(struct hda_codec *codec)
13730{
13731 struct alc_spec *spec = codec->spec;
13732 int err;
13733 static hda_nid_t alc268_ignore[] = { 0 };
13734
13735 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13736 alc268_ignore);
13737 if (err < 0)
13738 return err;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013739 if (!spec->autocfg.line_outs) {
13740 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
13741 spec->multiout.max_channels = 2;
13742 spec->no_analog = 1;
13743 goto dig_only;
13744 }
Kailang Yanga361d842007-06-05 12:30:55 +020013745 return 0; /* can't find valid BIOS pin config */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013746 }
Kailang Yanga361d842007-06-05 12:30:55 +020013747 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
13748 if (err < 0)
13749 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020013750 err = alc268_auto_create_input_ctls(codec, &spec->autocfg);
Kailang Yanga361d842007-06-05 12:30:55 +020013751 if (err < 0)
13752 return err;
13753
13754 spec->multiout.max_channels = 2;
13755
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013756 dig_only:
Kailang Yanga361d842007-06-05 12:30:55 +020013757 /* digital only support output */
Takashi Iwai757899a2010-07-30 10:48:14 +020013758 alc_auto_parse_digital(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +020013759 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013760 add_mixer(spec, spec->kctls.list);
Kailang Yanga361d842007-06-05 12:30:55 +020013761
Takashi Iwai892981f2009-03-02 08:04:35 +010013762 if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013763 add_mixer(spec, alc268_beep_mixer);
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013764
Takashi Iwaid88897e2008-10-31 15:01:37 +010013765 add_verb(spec, alc268_volume_init_verbs);
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030013766 spec->num_mux_defs = 2;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020013767 spec->input_mux = &spec->private_imux[0];
Kailang Yanga361d842007-06-05 12:30:55 +020013768
Takashi Iwai776e1842007-08-29 15:07:11 +020013769 err = alc_auto_add_mic_boost(codec);
13770 if (err < 0)
13771 return err;
13772
Kailang Yang6227cdc2010-02-25 08:36:52 +010013773 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai1d955eb2009-06-29 11:33:53 +020013774
Kailang Yanga361d842007-06-05 12:30:55 +020013775 return 1;
13776}
13777
Kailang Yanga361d842007-06-05 12:30:55 +020013778#define alc268_auto_init_analog_input alc882_auto_init_analog_input
13779
13780/* init callback for auto-configuration model -- overriding the default init */
13781static void alc268_auto_init(struct hda_codec *codec)
13782{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013783 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020013784 alc268_auto_init_multi_out(codec);
13785 alc268_auto_init_hp_out(codec);
13786 alc268_auto_init_mono_speaker_out(codec);
13787 alc268_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020013788 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013789 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020013790 alc_inithook(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020013791}
13792
13793/*
13794 * configuration and preset
13795 */
Takashi Iwaiea734962011-01-17 11:29:34 +010013796static const char * const alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013797 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020013798 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020013799 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020013800 [ALC268_ACER] = "acer",
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013801 [ALC268_ACER_DMIC] = "acer-dmic",
Kailang Yang8ef355d2008-08-26 13:10:22 +020013802 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013803 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013804 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013805#ifdef CONFIG_SND_DEBUG
13806 [ALC268_TEST] = "test",
13807#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013808 [ALC268_AUTO] = "auto",
13809};
13810
13811static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020013812 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013813 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010013814 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013815 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010013816 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020013817 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
13818 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013819 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Daniel T Chena1bf8082009-11-01 18:32:29 -050013820 SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0,
13821 "Dell Inspiron Mini9/Vostro A90", ALC268_DELL),
Takashi Iwai33d78672009-09-08 11:03:41 +020013822 /* almost compatible with toshiba but with optional digital outs;
13823 * auto-probing seems working fine
13824 */
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013825 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series",
Takashi Iwai33d78672009-09-08 11:03:41 +020013826 ALC268_AUTO),
Kailang Yanga361d842007-06-05 12:30:55 +020013827 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013828 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Tony Vroon378bd6a2008-06-04 12:08:30 +020013829 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020013830 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013831 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Kailang Yanga361d842007-06-05 12:30:55 +020013832 {}
13833};
13834
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013835/* Toshiba laptops have no unique PCI SSID but only codec SSID */
13836static struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
13837 SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO),
13838 SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO),
13839 SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
13840 ALC268_TOSHIBA),
13841 {}
13842};
13843
Kailang Yanga361d842007-06-05 12:30:55 +020013844static struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013845 [ALC267_QUANTA_IL1] = {
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013846 .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer,
13847 alc268_capture_nosrc_mixer },
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013848 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13849 alc267_quanta_il1_verbs },
13850 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13851 .dac_nids = alc268_dac_nids,
13852 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13853 .adc_nids = alc268_adc_nids_alt,
13854 .hp_nid = 0x03,
13855 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13856 .channel_mode = alc268_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013857 .unsol_event = alc_sku_unsol_event,
13858 .setup = alc267_quanta_il1_setup,
13859 .init_hook = alc_inithook,
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013860 },
Kailang Yanga361d842007-06-05 12:30:55 +020013861 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013862 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13863 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020013864 .init_verbs = { alc268_base_init_verbs },
13865 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13866 .dac_nids = alc268_dac_nids,
13867 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13868 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013869 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020013870 .hp_nid = 0x03,
13871 .dig_out_nid = ALC268_DIGOUT_NID,
13872 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13873 .channel_mode = alc268_modes,
13874 .input_mux = &alc268_capture_source,
13875 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013876 [ALC268_TOSHIBA] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020013877 .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013878 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013879 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13880 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013881 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13882 .dac_nids = alc268_dac_nids,
13883 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13884 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013885 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013886 .hp_nid = 0x03,
13887 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13888 .channel_mode = alc268_modes,
13889 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020013890 .unsol_event = alc268_toshiba_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013891 .setup = alc268_toshiba_setup,
13892 .init_hook = alc268_toshiba_automute,
Takashi Iwaid2738092007-08-16 14:59:45 +020013893 },
13894 [ALC268_ACER] = {
Takashi Iwai432fd132009-09-30 08:13:44 +020013895 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013896 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013897 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13898 alc268_acer_verbs },
13899 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13900 .dac_nids = alc268_dac_nids,
13901 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13902 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013903 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020013904 .hp_nid = 0x02,
13905 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13906 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013907 .input_mux = &alc268_acer_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020013908 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020013909 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013910 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013911 [ALC268_ACER_DMIC] = {
13912 .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
13913 alc268_beep_mixer },
13914 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13915 alc268_acer_verbs },
13916 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13917 .dac_nids = alc268_dac_nids,
13918 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13919 .adc_nids = alc268_adc_nids_alt,
13920 .capsrc_nids = alc268_capsrc_nids,
13921 .hp_nid = 0x02,
13922 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13923 .channel_mode = alc268_modes,
13924 .input_mux = &alc268_acer_dmic_capture_source,
13925 .unsol_event = alc268_acer_unsol_event,
13926 .init_hook = alc268_acer_init_hook,
13927 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013928 [ALC268_ACER_ASPIRE_ONE] = {
13929 .mixers = { alc268_acer_aspire_one_mixer,
Takashi Iwai22971e32009-02-10 11:56:44 +010013930 alc268_beep_mixer,
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013931 alc268_capture_nosrc_mixer },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013932 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13933 alc268_acer_aspire_one_verbs },
13934 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13935 .dac_nids = alc268_dac_nids,
13936 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13937 .adc_nids = alc268_adc_nids_alt,
13938 .capsrc_nids = alc268_capsrc_nids,
13939 .hp_nid = 0x03,
13940 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13941 .channel_mode = alc268_modes,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013942 .unsol_event = alc268_acer_lc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013943 .setup = alc268_acer_lc_setup,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013944 .init_hook = alc268_acer_lc_init_hook,
13945 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013946 [ALC268_DELL] = {
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013947 .mixers = { alc268_dell_mixer, alc268_beep_mixer,
13948 alc268_capture_nosrc_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013949 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13950 alc268_dell_verbs },
13951 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13952 .dac_nids = alc268_dac_nids,
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013953 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13954 .adc_nids = alc268_adc_nids_alt,
13955 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013956 .hp_nid = 0x02,
13957 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13958 .channel_mode = alc268_modes,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013959 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013960 .setup = alc268_dell_setup,
13961 .init_hook = alc_inithook,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013962 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013963 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013964 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13965 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013966 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13967 alc268_toshiba_verbs },
13968 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13969 .dac_nids = alc268_dac_nids,
13970 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13971 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013972 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013973 .hp_nid = 0x03,
13974 .dig_out_nid = ALC268_DIGOUT_NID,
13975 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13976 .channel_mode = alc268_modes,
13977 .input_mux = &alc268_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013978 .setup = alc268_toshiba_setup,
13979 .init_hook = alc268_toshiba_automute,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013980 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013981#ifdef CONFIG_SND_DEBUG
13982 [ALC268_TEST] = {
13983 .mixers = { alc268_test_mixer, alc268_capture_mixer },
13984 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13985 alc268_volume_init_verbs },
13986 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13987 .dac_nids = alc268_dac_nids,
13988 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13989 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013990 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013991 .hp_nid = 0x03,
13992 .dig_out_nid = ALC268_DIGOUT_NID,
13993 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13994 .channel_mode = alc268_modes,
13995 .input_mux = &alc268_capture_source,
13996 },
13997#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013998};
13999
14000static int patch_alc268(struct hda_codec *codec)
14001{
14002 struct alc_spec *spec;
14003 int board_config;
Takashi Iwai22971e32009-02-10 11:56:44 +010014004 int i, has_beep, err;
Kailang Yanga361d842007-06-05 12:30:55 +020014005
Julia Lawallef86f582009-12-19 08:18:03 +010014006 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yanga361d842007-06-05 12:30:55 +020014007 if (spec == NULL)
14008 return -ENOMEM;
14009
14010 codec->spec = spec;
14011
14012 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
14013 alc268_models,
14014 alc268_cfg_tbl);
14015
Takashi Iwai3abf2f32009-08-19 20:05:02 +020014016 if (board_config < 0 || board_config >= ALC268_MODEL_LAST)
14017 board_config = snd_hda_check_board_codec_sid_config(codec,
Takashi Iwai50ae0aa2010-03-08 12:09:59 +010014018 ALC268_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl);
Takashi Iwai3abf2f32009-08-19 20:05:02 +020014019
Kailang Yanga361d842007-06-05 12:30:55 +020014020 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020014021 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
14022 codec->chip_name);
Kailang Yanga361d842007-06-05 12:30:55 +020014023 board_config = ALC268_AUTO;
14024 }
14025
14026 if (board_config == ALC268_AUTO) {
14027 /* automatic parse from the BIOS config */
14028 err = alc268_parse_auto_config(codec);
14029 if (err < 0) {
14030 alc_free(codec);
14031 return err;
14032 } else if (!err) {
14033 printk(KERN_INFO
14034 "hda_codec: Cannot set up configuration "
14035 "from BIOS. Using base mode...\n");
14036 board_config = ALC268_3ST;
14037 }
14038 }
14039
14040 if (board_config != ALC268_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020014041 setup_preset(codec, &alc268_presets[board_config]);
Kailang Yanga361d842007-06-05 12:30:55 +020014042
Kailang Yanga361d842007-06-05 12:30:55 +020014043 spec->stream_analog_playback = &alc268_pcm_analog_playback;
14044 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010014045 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020014046
Kailang Yanga361d842007-06-05 12:30:55 +020014047 spec->stream_digital_playback = &alc268_pcm_digital_playback;
14048
Takashi Iwai22971e32009-02-10 11:56:44 +010014049 has_beep = 0;
14050 for (i = 0; i < spec->num_mixers; i++) {
14051 if (spec->mixers[i] == alc268_beep_mixer) {
14052 has_beep = 1;
14053 break;
14054 }
14055 }
14056
14057 if (has_beep) {
14058 err = snd_hda_attach_beep_device(codec, 0x1);
14059 if (err < 0) {
14060 alc_free(codec);
14061 return err;
14062 }
14063 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
14064 /* override the amp caps for beep generator */
14065 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010014066 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
14067 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
14068 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
14069 (0 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwai22971e32009-02-10 11:56:44 +010014070 }
Takashi Iwaiaef9d312008-02-19 13:16:41 +010014071
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010014072 if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010014073 /* check whether NID 0x07 is valid */
14074 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwai85860c02008-02-19 15:00:15 +010014075 int i;
Kailang Yanga361d842007-06-05 12:30:55 +020014076
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020014077 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010014078 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020014079 wcap = get_wcaps_type(wcap);
Takashi Iwaifdbc6622009-08-19 00:18:10 +020014080 if (spec->auto_mic ||
14081 wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010014082 spec->adc_nids = alc268_adc_nids_alt;
14083 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020014084 if (spec->auto_mic)
14085 fixup_automic_adc(codec);
Takashi Iwaifdbc6622009-08-19 00:18:10 +020014086 if (spec->auto_mic || spec->input_mux->num_items == 1)
14087 add_mixer(spec, alc268_capture_nosrc_mixer);
14088 else
14089 add_mixer(spec, alc268_capture_alt_mixer);
Takashi Iwai3866f0b2008-01-15 12:37:42 +010014090 } else {
14091 spec->adc_nids = alc268_adc_nids;
14092 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
Takashi Iwaid88897e2008-10-31 15:01:37 +010014093 add_mixer(spec, alc268_capture_mixer);
Kailang Yanga361d842007-06-05 12:30:55 +020014094 }
Takashi Iwai85860c02008-02-19 15:00:15 +010014095 /* set default input source */
14096 for (i = 0; i < spec->num_adc_nids; i++)
14097 snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
14098 0, AC_VERB_SET_CONNECT_SEL,
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030014099 i < spec->num_mux_defs ?
14100 spec->input_mux[i].items[0].index :
Takashi Iwai85860c02008-02-19 15:00:15 +010014101 spec->input_mux->items[0].index);
Kailang Yanga361d842007-06-05 12:30:55 +020014102 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010014103
14104 spec->vmaster_nid = 0x02;
14105
Kailang Yanga361d842007-06-05 12:30:55 +020014106 codec->patch_ops = alc_patch_ops;
14107 if (board_config == ALC268_AUTO)
14108 spec->init_hook = alc268_auto_init;
Kailang Yangea1fb292008-08-26 12:58:38 +020014109
Kailang Yangbf1b0222010-10-21 08:49:56 +020014110 alc_init_jacks(codec);
14111
Kailang Yanga361d842007-06-05 12:30:55 +020014112 return 0;
14113}
14114
14115/*
Kailang Yangf6a92242007-12-13 16:52:54 +010014116 * ALC269 channel source setting (2 channel)
14117 */
14118#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
14119
14120#define alc269_dac_nids alc260_dac_nids
14121
14122static hda_nid_t alc269_adc_nids[1] = {
14123 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020014124 0x08,
14125};
14126
Takashi Iwaie01bf502008-08-21 16:25:07 +020014127static hda_nid_t alc269_capsrc_nids[1] = {
14128 0x23,
14129};
14130
Kailang Yang84898e82010-02-04 14:16:14 +010014131static hda_nid_t alc269vb_adc_nids[1] = {
14132 /* ADC1 */
14133 0x09,
14134};
14135
14136static hda_nid_t alc269vb_capsrc_nids[1] = {
14137 0x22,
14138};
14139
Takashi Iwai66946352010-03-29 17:21:45 +020014140static hda_nid_t alc269_adc_candidates[] = {
14141 0x08, 0x09, 0x07,
14142};
Takashi Iwaie01bf502008-08-21 16:25:07 +020014143
Kailang Yangf6a92242007-12-13 16:52:54 +010014144#define alc269_modes alc260_modes
14145#define alc269_capture_source alc880_lg_lw_capture_source
14146
14147static struct snd_kcontrol_new alc269_base_mixer[] = {
14148 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14149 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14150 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14151 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14152 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14153 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014154 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangf6a92242007-12-13 16:52:54 +010014155 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
14156 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014157 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangf6a92242007-12-13 16:52:54 +010014158 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
14159 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
14160 { } /* end */
14161};
14162
Kailang Yang60db6b52008-08-26 13:13:00 +020014163static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
14164 /* output mixer control */
14165 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
14166 {
14167 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14168 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010014169 .subdevice = HDA_SUBDEV_AMP_FLAG,
Kailang Yang60db6b52008-08-26 13:13:00 +020014170 .info = snd_hda_mixer_amp_switch_info,
14171 .get = snd_hda_mixer_amp_switch_get,
14172 .put = alc268_acer_master_sw_put,
14173 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14174 },
14175 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14176 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014177 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020014178 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
14179 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014180 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020014181 { }
14182};
14183
Tony Vroon64154832008-11-06 15:08:49 +000014184static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
14185 /* output mixer control */
14186 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
14187 {
14188 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14189 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010014190 .subdevice = HDA_SUBDEV_AMP_FLAG,
Tony Vroon64154832008-11-06 15:08:49 +000014191 .info = snd_hda_mixer_amp_switch_info,
14192 .get = snd_hda_mixer_amp_switch_get,
14193 .put = alc268_acer_master_sw_put,
14194 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14195 },
14196 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14197 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014198 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000014199 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
14200 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014201 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000014202 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
14203 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014204 HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x1b, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000014205 { }
14206};
14207
Kailang Yang84898e82010-02-04 14:16:14 +010014208static struct snd_kcontrol_new alc269_laptop_mixer[] = {
Takashi Iwaiaa202452009-07-03 15:00:54 +020014209 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010014210 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwaiaa202452009-07-03 15:00:54 +020014211 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010014212 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yangf53281e2008-07-18 12:36:43 +020014213 { } /* end */
14214};
14215
Kailang Yang84898e82010-02-04 14:16:14 +010014216static struct snd_kcontrol_new alc269vb_laptop_mixer[] = {
14217 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14218 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14219 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
14220 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14221 { } /* end */
14222};
14223
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014224static struct snd_kcontrol_new alc269_asus_mixer[] = {
14225 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14226 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x0, HDA_INPUT),
14227 { } /* end */
14228};
14229
Kailang Yangf6a92242007-12-13 16:52:54 +010014230/* capture mixer elements */
Kailang Yang84898e82010-02-04 14:16:14 +010014231static struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
14232 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
14233 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014234 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
14235 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang84898e82010-02-04 14:16:14 +010014236 { } /* end */
14237};
14238
14239static struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = {
Kailang Yangf53281e2008-07-18 12:36:43 +020014240 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
14241 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014242 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai26f5df22008-11-03 17:39:46 +010014243 { } /* end */
14244};
14245
Kailang Yang84898e82010-02-04 14:16:14 +010014246static struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
14247 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
14248 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014249 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
14250 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang84898e82010-02-04 14:16:14 +010014251 { } /* end */
14252};
14253
14254static struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
14255 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
14256 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014257 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang84898e82010-02-04 14:16:14 +010014258 { } /* end */
14259};
14260
Takashi Iwai26f5df22008-11-03 17:39:46 +010014261/* FSC amilo */
Kailang Yang84898e82010-02-04 14:16:14 +010014262#define alc269_fujitsu_mixer alc269_laptop_mixer
Kailang Yangf53281e2008-07-18 12:36:43 +020014263
Kailang Yang60db6b52008-08-26 13:13:00 +020014264static struct hda_verb alc269_quanta_fl1_verbs[] = {
14265 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14266 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14267 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14268 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
14269 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14270 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14271 { }
14272};
14273
Tony Vroon64154832008-11-06 15:08:49 +000014274static struct hda_verb alc269_lifebook_verbs[] = {
14275 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14276 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
14277 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14278 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14279 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
14280 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14281 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14282 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
14283 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14284 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14285 { }
14286};
14287
Kailang Yang60db6b52008-08-26 13:13:00 +020014288/* toggle speaker-output according to the hp-jack state */
14289static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
14290{
14291 unsigned int present;
14292 unsigned char bits;
14293
Wu Fengguang864f92b2009-11-18 12:38:02 +080014294 present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014295 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang60db6b52008-08-26 13:13:00 +020014296 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014297 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020014298 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014299 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020014300
14301 snd_hda_codec_write(codec, 0x20, 0,
14302 AC_VERB_SET_COEF_INDEX, 0x0c);
14303 snd_hda_codec_write(codec, 0x20, 0,
14304 AC_VERB_SET_PROC_COEF, 0x680);
14305
14306 snd_hda_codec_write(codec, 0x20, 0,
14307 AC_VERB_SET_COEF_INDEX, 0x0c);
14308 snd_hda_codec_write(codec, 0x20, 0,
14309 AC_VERB_SET_PROC_COEF, 0x480);
14310}
14311
Tony Vroon64154832008-11-06 15:08:49 +000014312/* toggle speaker-output according to the hp-jacks state */
14313static void alc269_lifebook_speaker_automute(struct hda_codec *codec)
14314{
14315 unsigned int present;
14316 unsigned char bits;
14317
14318 /* Check laptop headphone socket */
Wu Fengguang864f92b2009-11-18 12:38:02 +080014319 present = snd_hda_jack_detect(codec, 0x15);
Tony Vroon64154832008-11-06 15:08:49 +000014320
14321 /* Check port replicator headphone socket */
Wu Fengguang864f92b2009-11-18 12:38:02 +080014322 present |= snd_hda_jack_detect(codec, 0x1a);
Tony Vroon64154832008-11-06 15:08:49 +000014323
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014324 bits = present ? HDA_AMP_MUTE : 0;
Tony Vroon64154832008-11-06 15:08:49 +000014325 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014326 HDA_AMP_MUTE, bits);
Tony Vroon64154832008-11-06 15:08:49 +000014327 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014328 HDA_AMP_MUTE, bits);
Tony Vroon64154832008-11-06 15:08:49 +000014329
14330 snd_hda_codec_write(codec, 0x20, 0,
14331 AC_VERB_SET_COEF_INDEX, 0x0c);
14332 snd_hda_codec_write(codec, 0x20, 0,
14333 AC_VERB_SET_PROC_COEF, 0x680);
14334
14335 snd_hda_codec_write(codec, 0x20, 0,
14336 AC_VERB_SET_COEF_INDEX, 0x0c);
14337 snd_hda_codec_write(codec, 0x20, 0,
14338 AC_VERB_SET_PROC_COEF, 0x480);
14339}
14340
Tony Vroon64154832008-11-06 15:08:49 +000014341static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
14342{
14343 unsigned int present_laptop;
14344 unsigned int present_dock;
14345
Wu Fengguang864f92b2009-11-18 12:38:02 +080014346 present_laptop = snd_hda_jack_detect(codec, 0x18);
14347 present_dock = snd_hda_jack_detect(codec, 0x1b);
Tony Vroon64154832008-11-06 15:08:49 +000014348
14349 /* Laptop mic port overrides dock mic port, design decision */
14350 if (present_dock)
14351 snd_hda_codec_write(codec, 0x23, 0,
14352 AC_VERB_SET_CONNECT_SEL, 0x3);
14353 if (present_laptop)
14354 snd_hda_codec_write(codec, 0x23, 0,
14355 AC_VERB_SET_CONNECT_SEL, 0x0);
14356 if (!present_dock && !present_laptop)
14357 snd_hda_codec_write(codec, 0x23, 0,
14358 AC_VERB_SET_CONNECT_SEL, 0x1);
14359}
14360
Kailang Yang60db6b52008-08-26 13:13:00 +020014361static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
14362 unsigned int res)
14363{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014364 switch (res >> 26) {
14365 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020014366 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014367 break;
14368 case ALC880_MIC_EVENT:
14369 alc_mic_automute(codec);
14370 break;
14371 }
Kailang Yang60db6b52008-08-26 13:13:00 +020014372}
14373
Tony Vroon64154832008-11-06 15:08:49 +000014374static void alc269_lifebook_unsol_event(struct hda_codec *codec,
14375 unsigned int res)
14376{
14377 if ((res >> 26) == ALC880_HP_EVENT)
14378 alc269_lifebook_speaker_automute(codec);
14379 if ((res >> 26) == ALC880_MIC_EVENT)
14380 alc269_lifebook_mic_autoswitch(codec);
14381}
14382
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014383static void alc269_quanta_fl1_setup(struct hda_codec *codec)
14384{
14385 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010014386 spec->autocfg.hp_pins[0] = 0x15;
14387 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014388 spec->ext_mic.pin = 0x18;
14389 spec->ext_mic.mux_idx = 0;
14390 spec->int_mic.pin = 0x19;
14391 spec->int_mic.mux_idx = 1;
14392 spec->auto_mic = 1;
14393}
14394
Kailang Yang60db6b52008-08-26 13:13:00 +020014395static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
14396{
14397 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014398 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020014399}
14400
Tony Vroon64154832008-11-06 15:08:49 +000014401static void alc269_lifebook_init_hook(struct hda_codec *codec)
14402{
14403 alc269_lifebook_speaker_automute(codec);
14404 alc269_lifebook_mic_autoswitch(codec);
14405}
14406
Kailang Yang84898e82010-02-04 14:16:14 +010014407static struct hda_verb alc269_laptop_dmic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014408 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14409 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
14410 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14411 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14412 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14413 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14414 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14415 {}
14416};
14417
Kailang Yang84898e82010-02-04 14:16:14 +010014418static struct hda_verb alc269_laptop_amic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014419 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14420 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
14421 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14422 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
14423 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14424 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14425 {}
14426};
14427
Kailang Yang84898e82010-02-04 14:16:14 +010014428static struct hda_verb alc269vb_laptop_dmic_init_verbs[] = {
14429 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
14430 {0x22, AC_VERB_SET_CONNECT_SEL, 0x06},
14431 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14432 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14433 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14434 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14435 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14436 {}
14437};
14438
14439static struct hda_verb alc269vb_laptop_amic_init_verbs[] = {
14440 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
14441 {0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
14442 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14443 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14444 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14445 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14446 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14447 {}
14448};
14449
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014450static struct hda_verb alc271_acer_dmic_verbs[] = {
14451 {0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
14452 {0x20, AC_VERB_SET_PROC_COEF, 0x4000},
14453 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14454 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14455 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14456 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14457 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00},
14458 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14459 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14460 {0x22, AC_VERB_SET_CONNECT_SEL, 6},
14461 { }
14462};
14463
Kailang Yang60db6b52008-08-26 13:13:00 +020014464/* toggle speaker-output according to the hp-jack state */
14465static void alc269_speaker_automute(struct hda_codec *codec)
14466{
Kailang Yangebb83ee2009-12-17 12:23:00 +010014467 struct alc_spec *spec = codec->spec;
14468 unsigned int nid = spec->autocfg.hp_pins[0];
Kailang Yang60db6b52008-08-26 13:13:00 +020014469 unsigned int present;
14470 unsigned char bits;
14471
Kailang Yangebb83ee2009-12-17 12:23:00 +010014472 present = snd_hda_jack_detect(codec, nid);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014473 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang60db6b52008-08-26 13:13:00 +020014474 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014475 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020014476 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014477 HDA_AMP_MUTE, bits);
Kailang Yangbf1b0222010-10-21 08:49:56 +020014478 alc_report_jack(codec, nid);
Kailang Yang60db6b52008-08-26 13:13:00 +020014479}
14480
Kailang Yang60db6b52008-08-26 13:13:00 +020014481/* unsolicited event for HP jack sensing */
Kailang Yang84898e82010-02-04 14:16:14 +010014482static void alc269_laptop_unsol_event(struct hda_codec *codec,
Kailang Yang60db6b52008-08-26 13:13:00 +020014483 unsigned int res)
14484{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014485 switch (res >> 26) {
14486 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020014487 alc269_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014488 break;
14489 case ALC880_MIC_EVENT:
14490 alc_mic_automute(codec);
14491 break;
14492 }
Kailang Yang60db6b52008-08-26 13:13:00 +020014493}
14494
Kailang Yang226b1ec2010-04-09 11:01:20 +020014495static void alc269_laptop_amic_setup(struct hda_codec *codec)
14496{
14497 struct alc_spec *spec = codec->spec;
14498 spec->autocfg.hp_pins[0] = 0x15;
14499 spec->autocfg.speaker_pins[0] = 0x14;
14500 spec->ext_mic.pin = 0x18;
14501 spec->ext_mic.mux_idx = 0;
14502 spec->int_mic.pin = 0x19;
14503 spec->int_mic.mux_idx = 1;
14504 spec->auto_mic = 1;
14505}
14506
Kailang Yang84898e82010-02-04 14:16:14 +010014507static void alc269_laptop_dmic_setup(struct hda_codec *codec)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014508{
14509 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010014510 spec->autocfg.hp_pins[0] = 0x15;
14511 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014512 spec->ext_mic.pin = 0x18;
14513 spec->ext_mic.mux_idx = 0;
14514 spec->int_mic.pin = 0x12;
14515 spec->int_mic.mux_idx = 5;
14516 spec->auto_mic = 1;
14517}
14518
Kailang Yang226b1ec2010-04-09 11:01:20 +020014519static void alc269vb_laptop_amic_setup(struct hda_codec *codec)
Kailang Yang84898e82010-02-04 14:16:14 +010014520{
14521 struct alc_spec *spec = codec->spec;
Kailang Yang226b1ec2010-04-09 11:01:20 +020014522 spec->autocfg.hp_pins[0] = 0x21;
Takashi Iwai20645d72010-03-02 11:14:01 +010014523 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014524 spec->ext_mic.pin = 0x18;
14525 spec->ext_mic.mux_idx = 0;
14526 spec->int_mic.pin = 0x19;
14527 spec->int_mic.mux_idx = 1;
14528 spec->auto_mic = 1;
14529}
14530
Kailang Yang226b1ec2010-04-09 11:01:20 +020014531static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
14532{
14533 struct alc_spec *spec = codec->spec;
14534 spec->autocfg.hp_pins[0] = 0x21;
14535 spec->autocfg.speaker_pins[0] = 0x14;
14536 spec->ext_mic.pin = 0x18;
14537 spec->ext_mic.mux_idx = 0;
14538 spec->int_mic.pin = 0x12;
14539 spec->int_mic.mux_idx = 6;
14540 spec->auto_mic = 1;
14541}
14542
Kailang Yang84898e82010-02-04 14:16:14 +010014543static void alc269_laptop_inithook(struct hda_codec *codec)
Kailang Yang60db6b52008-08-26 13:13:00 +020014544{
14545 alc269_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014546 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020014547}
14548
Kailang Yangf6a92242007-12-13 16:52:54 +010014549/*
14550 * generic initialization of ADC, input mixers and output mixers
14551 */
14552static struct hda_verb alc269_init_verbs[] = {
14553 /*
14554 * Unmute ADC0 and set the default input to mic-in
14555 */
Kailang Yang84898e82010-02-04 14:16:14 +010014556 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010014557
14558 /*
Kailang Yang84898e82010-02-04 14:16:14 +010014559 * Set up output mixers (0x02 - 0x03)
Kailang Yangf6a92242007-12-13 16:52:54 +010014560 */
14561 /* set vol=0 to output mixers */
14562 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14563 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14564
14565 /* set up input amps for analog loopback */
14566 /* Amp Indices: DAC = 0, mixer = 1 */
14567 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14568 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14569 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14570 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14571 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14572 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14573
14574 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14575 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14576 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14577 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14578 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14579 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14580 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14581
14582 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14583 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf6a92242007-12-13 16:52:54 +010014584
Kailang Yang84898e82010-02-04 14:16:14 +010014585 /* FIXME: use Mux-type input source selection */
Kailang Yangf6a92242007-12-13 16:52:54 +010014586 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14587 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang84898e82010-02-04 14:16:14 +010014588 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangf6a92242007-12-13 16:52:54 +010014589
14590 /* set EAPD */
14591 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yang84898e82010-02-04 14:16:14 +010014592 { }
14593};
14594
14595static struct hda_verb alc269vb_init_verbs[] = {
14596 /*
14597 * Unmute ADC0 and set the default input to mic-in
14598 */
14599 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14600
14601 /*
14602 * Set up output mixers (0x02 - 0x03)
14603 */
14604 /* set vol=0 to output mixers */
14605 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14606 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14607
14608 /* set up input amps for analog loopback */
14609 /* Amp Indices: DAC = 0, mixer = 1 */
14610 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14611 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14612 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14613 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14614 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14615 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14616
14617 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14618 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14619 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14620 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14621 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14622 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14623 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14624
14625 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14626 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14627
14628 /* FIXME: use Mux-type input source selection */
14629 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14630 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
14631 {0x22, AC_VERB_SET_CONNECT_SEL, 0x00},
14632
14633 /* set EAPD */
14634 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yangf6a92242007-12-13 16:52:54 +010014635 { }
14636};
14637
Takashi Iwai9d0b71b2009-08-24 14:10:30 +020014638#define alc269_auto_create_multi_out_ctls \
14639 alc268_auto_create_multi_out_ctls
Takashi Iwai05f5f472009-08-25 13:10:18 +020014640#define alc269_auto_create_input_ctls \
14641 alc268_auto_create_input_ctls
Kailang Yangf6a92242007-12-13 16:52:54 +010014642
14643#ifdef CONFIG_SND_HDA_POWER_SAVE
14644#define alc269_loopbacks alc880_loopbacks
14645#endif
14646
Sasha Alexandrdef319f2009-06-16 16:00:15 -040014647/* pcm configuration: identical with ALC880 */
Kailang Yangf6a92242007-12-13 16:52:54 +010014648#define alc269_pcm_analog_playback alc880_pcm_analog_playback
14649#define alc269_pcm_analog_capture alc880_pcm_analog_capture
14650#define alc269_pcm_digital_playback alc880_pcm_digital_playback
14651#define alc269_pcm_digital_capture alc880_pcm_digital_capture
14652
Takashi Iwaif03d3112009-03-05 14:18:16 +010014653static struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
14654 .substreams = 1,
14655 .channels_min = 2,
14656 .channels_max = 8,
14657 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14658 /* NID is set in alc_build_pcms */
14659 .ops = {
14660 .open = alc880_playback_pcm_open,
14661 .prepare = alc880_playback_pcm_prepare,
14662 .cleanup = alc880_playback_pcm_cleanup
14663 },
14664};
14665
14666static struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
14667 .substreams = 1,
14668 .channels_min = 2,
14669 .channels_max = 2,
14670 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14671 /* NID is set in alc_build_pcms */
14672};
14673
Takashi Iwaiad358792010-03-30 18:00:59 +020014674#ifdef CONFIG_SND_HDA_POWER_SAVE
14675static int alc269_mic2_for_mute_led(struct hda_codec *codec)
14676{
14677 switch (codec->subsystem_id) {
14678 case 0x103c1586:
14679 return 1;
14680 }
14681 return 0;
14682}
14683
14684static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
14685{
14686 /* update mute-LED according to the speaker mute state */
14687 if (nid == 0x01 || nid == 0x14) {
14688 int pinval;
14689 if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) &
14690 HDA_AMP_MUTE)
14691 pinval = 0x24;
14692 else
14693 pinval = 0x20;
14694 /* mic2 vref pin is used for mute LED control */
Takashi Iwaia68d5a52010-03-30 18:03:44 +020014695 snd_hda_codec_update_cache(codec, 0x19, 0,
14696 AC_VERB_SET_PIN_WIDGET_CONTROL,
14697 pinval);
Takashi Iwaiad358792010-03-30 18:00:59 +020014698 }
14699 return alc_check_power_status(codec, nid);
14700}
14701#endif /* CONFIG_SND_HDA_POWER_SAVE */
14702
Takashi Iwai840b64c2010-07-13 22:49:01 +020014703static int alc275_setup_dual_adc(struct hda_codec *codec)
14704{
14705 struct alc_spec *spec = codec->spec;
14706
14707 if (codec->vendor_id != 0x10ec0275 || !spec->auto_mic)
14708 return 0;
14709 if ((spec->ext_mic.pin >= 0x18 && spec->int_mic.pin <= 0x13) ||
14710 (spec->ext_mic.pin <= 0x12 && spec->int_mic.pin >= 0x18)) {
14711 if (spec->ext_mic.pin <= 0x12) {
14712 spec->private_adc_nids[0] = 0x08;
14713 spec->private_adc_nids[1] = 0x11;
14714 spec->private_capsrc_nids[0] = 0x23;
14715 spec->private_capsrc_nids[1] = 0x22;
14716 } else {
14717 spec->private_adc_nids[0] = 0x11;
14718 spec->private_adc_nids[1] = 0x08;
14719 spec->private_capsrc_nids[0] = 0x22;
14720 spec->private_capsrc_nids[1] = 0x23;
14721 }
14722 spec->adc_nids = spec->private_adc_nids;
14723 spec->capsrc_nids = spec->private_capsrc_nids;
14724 spec->num_adc_nids = 2;
14725 spec->dual_adc_switch = 1;
14726 snd_printdd("realtek: enabling dual ADC switchg (%02x:%02x)\n",
14727 spec->adc_nids[0], spec->adc_nids[1]);
14728 return 1;
14729 }
14730 return 0;
14731}
14732
Takashi Iwaid433a672010-09-20 15:11:54 +020014733/* different alc269-variants */
14734enum {
14735 ALC269_TYPE_NORMAL,
Kailang Yang48c88e82010-11-23 08:56:16 +010014736 ALC269_TYPE_ALC258,
Takashi Iwaid433a672010-09-20 15:11:54 +020014737 ALC269_TYPE_ALC259,
Kailang Yang48c88e82010-11-23 08:56:16 +010014738 ALC269_TYPE_ALC269VB,
14739 ALC269_TYPE_ALC270,
Takashi Iwaid433a672010-09-20 15:11:54 +020014740 ALC269_TYPE_ALC271X,
14741};
14742
Kailang Yangf6a92242007-12-13 16:52:54 +010014743/*
14744 * BIOS auto configuration
14745 */
14746static int alc269_parse_auto_config(struct hda_codec *codec)
14747{
14748 struct alc_spec *spec = codec->spec;
Takashi Iwaicfb9fb52009-02-06 17:34:03 +010014749 int err;
Kailang Yangf6a92242007-12-13 16:52:54 +010014750 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
14751
14752 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
14753 alc269_ignore);
14754 if (err < 0)
14755 return err;
14756
14757 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
14758 if (err < 0)
14759 return err;
Takashi Iwaif3550d12010-09-20 15:09:03 +020014760 if (spec->codec_variant == ALC269_TYPE_NORMAL)
14761 err = alc269_auto_create_input_ctls(codec, &spec->autocfg);
14762 else
14763 err = alc_auto_create_input_ctls(codec, &spec->autocfg, 0,
14764 0x22, 0);
Kailang Yangf6a92242007-12-13 16:52:54 +010014765 if (err < 0)
14766 return err;
14767
14768 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
14769
Takashi Iwai757899a2010-07-30 10:48:14 +020014770 alc_auto_parse_digital(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014771
Takashi Iwai603c4012008-07-30 15:01:44 +020014772 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010014773 add_mixer(spec, spec->kctls.list);
Kailang Yangf6a92242007-12-13 16:52:54 +010014774
Takashi Iwaid433a672010-09-20 15:11:54 +020014775 if (spec->codec_variant != ALC269_TYPE_NORMAL) {
Kailang Yang84898e82010-02-04 14:16:14 +010014776 add_verb(spec, alc269vb_init_verbs);
Kailang Yang6227cdc2010-02-25 08:36:52 +010014777 alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21);
Kailang Yang84898e82010-02-04 14:16:14 +010014778 } else {
14779 add_verb(spec, alc269_init_verbs);
Kailang Yang6227cdc2010-02-25 08:36:52 +010014780 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Kailang Yang84898e82010-02-04 14:16:14 +010014781 }
14782
Kailang Yangf6a92242007-12-13 16:52:54 +010014783 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020014784 spec->input_mux = &spec->private_imux[0];
Takashi Iwai840b64c2010-07-13 22:49:01 +020014785
14786 if (!alc275_setup_dual_adc(codec))
14787 fillup_priv_adc_nids(codec, alc269_adc_candidates,
14788 sizeof(alc269_adc_candidates));
Takashi Iwai66946352010-03-29 17:21:45 +020014789
Takashi Iwaie01bf502008-08-21 16:25:07 +020014790 /* set default input source */
Takashi Iwai840b64c2010-07-13 22:49:01 +020014791 if (!spec->dual_adc_switch)
Takashi Iwai748cce42010-08-04 07:37:39 +020014792 select_or_unmute_capsrc(codec, spec->capsrc_nids[0],
14793 spec->input_mux->items[0].index);
Kailang Yangf6a92242007-12-13 16:52:54 +010014794
14795 err = alc_auto_add_mic_boost(codec);
14796 if (err < 0)
14797 return err;
14798
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010014799 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020014800 set_capture_mixer(codec);
Kailang Yangf53281e2008-07-18 12:36:43 +020014801
Kailang Yangf6a92242007-12-13 16:52:54 +010014802 return 1;
14803}
14804
Takashi Iwaie9af4f32009-08-29 23:23:08 +020014805#define alc269_auto_init_multi_out alc268_auto_init_multi_out
14806#define alc269_auto_init_hp_out alc268_auto_init_hp_out
Kailang Yangf6a92242007-12-13 16:52:54 +010014807#define alc269_auto_init_analog_input alc882_auto_init_analog_input
14808
14809
14810/* init callback for auto-configuration model -- overriding the default init */
14811static void alc269_auto_init(struct hda_codec *codec)
14812{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014813 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010014814 alc269_auto_init_multi_out(codec);
14815 alc269_auto_init_hp_out(codec);
14816 alc269_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020014817 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014818 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020014819 alc_inithook(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014820}
14821
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014822#ifdef SND_HDA_NEEDS_RESUME
14823static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
14824{
14825 int val = alc_read_coef_idx(codec, 0x04);
14826 if (power_up)
14827 val |= 1 << 11;
14828 else
14829 val &= ~(1 << 11);
14830 alc_write_coef_idx(codec, 0x04, val);
14831}
14832
Kailang Yang977ddd62010-09-15 10:02:29 +020014833#ifdef CONFIG_SND_HDA_POWER_SAVE
14834static int alc269_suspend(struct hda_codec *codec, pm_message_t state)
14835{
14836 struct alc_spec *spec = codec->spec;
Kailang Yang977ddd62010-09-15 10:02:29 +020014837
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014838 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017)
14839 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014840 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014841 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014842 msleep(150);
14843 }
14844
14845 alc_shutup(codec);
14846 if (spec && spec->power_hook)
14847 spec->power_hook(codec);
14848 return 0;
14849}
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014850#endif /* CONFIG_SND_HDA_POWER_SAVE */
14851
Kailang Yang977ddd62010-09-15 10:02:29 +020014852static int alc269_resume(struct hda_codec *codec)
14853{
Kailang Yang977ddd62010-09-15 10:02:29 +020014854 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014855 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014856 msleep(150);
14857 }
14858
14859 codec->patch_ops.init(codec);
14860
14861 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014862 alc269_toggle_power_output(codec, 1);
Kailang Yang977ddd62010-09-15 10:02:29 +020014863 msleep(200);
14864 }
14865
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014866 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018)
14867 alc269_toggle_power_output(codec, 1);
Kailang Yang977ddd62010-09-15 10:02:29 +020014868
14869 snd_hda_codec_resume_amp(codec);
14870 snd_hda_codec_resume_cache(codec);
Takashi Iwai9e5341b2010-09-21 09:57:06 +020014871 hda_call_check_power_status(codec, 0x01);
Kailang Yang977ddd62010-09-15 10:02:29 +020014872 return 0;
14873}
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014874#endif /* SND_HDA_NEEDS_RESUME */
Kailang Yang977ddd62010-09-15 10:02:29 +020014875
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014876static void alc269_fixup_hweq(struct hda_codec *codec,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014877 const struct alc_fixup *fix, int action)
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014878{
14879 int coef;
14880
Takashi Iwai58701122011-01-13 15:41:45 +010014881 if (action != ALC_FIXUP_ACT_INIT)
Takashi Iwai9fb1ef22011-01-13 14:40:43 +010014882 return;
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014883 coef = alc_read_coef_idx(codec, 0x1e);
14884 alc_write_coef_idx(codec, 0x1e, coef | 0x80);
14885}
14886
Takashi Iwaiff818c22010-04-12 08:59:25 +020014887enum {
14888 ALC269_FIXUP_SONY_VAIO,
Takashi Iwai74dc8902011-01-13 14:14:41 +010014889 ALC275_FIXUP_SONY_VAIO_GPIO2,
David Henningsson145a9022010-09-16 10:07:53 +020014890 ALC269_FIXUP_DELL_M101Z,
David Henningsson022c92b2010-12-17 20:43:04 +010014891 ALC269_FIXUP_SKU_IGNORE,
David Henningssonac612402010-12-15 09:18:18 +010014892 ALC269_FIXUP_ASUS_G73JW,
Kailang Yang357f9152011-01-12 08:12:52 +010014893 ALC269_FIXUP_LENOVO_EAPD,
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014894 ALC275_FIXUP_SONY_HWEQ,
Takashi Iwaiff818c22010-04-12 08:59:25 +020014895};
14896
Takashi Iwaiff818c22010-04-12 08:59:25 +020014897static const struct alc_fixup alc269_fixups[] = {
14898 [ALC269_FIXUP_SONY_VAIO] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014899 .type = ALC_FIXUP_VERBS,
14900 .v.verbs = (const struct hda_verb[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020014901 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
14902 {}
14903 }
Takashi Iwaiff818c22010-04-12 08:59:25 +020014904 },
Takashi Iwai74dc8902011-01-13 14:14:41 +010014905 [ALC275_FIXUP_SONY_VAIO_GPIO2] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014906 .type = ALC_FIXUP_VERBS,
14907 .v.verbs = (const struct hda_verb[]) {
Kailang Yang27855912010-12-21 09:09:53 +010014908 {0x01, AC_VERB_SET_GPIO_MASK, 0x04},
14909 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04},
14910 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
14911 { }
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014912 },
14913 .chained = true,
14914 .chain_id = ALC269_FIXUP_SONY_VAIO
Kailang Yang27855912010-12-21 09:09:53 +010014915 },
David Henningsson145a9022010-09-16 10:07:53 +020014916 [ALC269_FIXUP_DELL_M101Z] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014917 .type = ALC_FIXUP_VERBS,
14918 .v.verbs = (const struct hda_verb[]) {
David Henningsson145a9022010-09-16 10:07:53 +020014919 /* Enables internal speaker */
14920 {0x20, AC_VERB_SET_COEF_INDEX, 13},
14921 {0x20, AC_VERB_SET_PROC_COEF, 0x4040},
14922 {}
14923 }
14924 },
David Henningsson022c92b2010-12-17 20:43:04 +010014925 [ALC269_FIXUP_SKU_IGNORE] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014926 .type = ALC_FIXUP_SKU,
14927 .v.sku = ALC_FIXUP_SKU_IGNORE,
David Henningssonfe67b242010-12-15 08:01:46 +010014928 },
David Henningssonac612402010-12-15 09:18:18 +010014929 [ALC269_FIXUP_ASUS_G73JW] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014930 .type = ALC_FIXUP_PINS,
14931 .v.pins = (const struct alc_pincfg[]) {
David Henningssonac612402010-12-15 09:18:18 +010014932 { 0x17, 0x99130111 }, /* subwoofer */
14933 { }
14934 }
14935 },
Kailang Yang357f9152011-01-12 08:12:52 +010014936 [ALC269_FIXUP_LENOVO_EAPD] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014937 .type = ALC_FIXUP_VERBS,
14938 .v.verbs = (const struct hda_verb[]) {
Kailang Yang357f9152011-01-12 08:12:52 +010014939 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
14940 {}
14941 }
14942 },
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014943 [ALC275_FIXUP_SONY_HWEQ] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014944 .type = ALC_FIXUP_FUNC,
14945 .v.func = alc269_fixup_hweq,
14946 .chained = true,
14947 .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014948 }
Takashi Iwaiff818c22010-04-12 08:59:25 +020014949};
14950
14951static struct snd_pci_quirk alc269_fixup_tbl[] = {
Takashi Iwai74dc8902011-01-13 14:14:41 +010014952 SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014953 SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
14954 SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
Takashi Iwai7039c742010-12-23 16:35:34 +010014955 SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
David Henningsson145a9022010-09-16 10:07:53 +020014956 SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
David Henningsson022c92b2010-12-17 20:43:04 +010014957 SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
David Henningssonfb228af2011-01-19 11:59:01 +010014958 SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
David Henningsson022c92b2010-12-17 20:43:04 +010014959 SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
David Henningssonac612402010-12-15 09:18:18 +010014960 SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
Kailang Yang357f9152011-01-12 08:12:52 +010014961 SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
Takashi Iwaiff818c22010-04-12 08:59:25 +020014962 {}
14963};
14964
14965
Kailang Yangf6a92242007-12-13 16:52:54 +010014966/*
14967 * configuration and preset
14968 */
Takashi Iwaiea734962011-01-17 11:29:34 +010014969static const char * const alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014970 [ALC269_BASIC] = "basic",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020014971 [ALC269_QUANTA_FL1] = "quanta",
Kailang Yang84898e82010-02-04 14:16:14 +010014972 [ALC269_AMIC] = "laptop-amic",
14973 [ALC269_DMIC] = "laptop-dmic",
Tony Vroon64154832008-11-06 15:08:49 +000014974 [ALC269_FUJITSU] = "fujitsu",
Takashi Iwai3d3792c2009-09-11 07:50:47 +020014975 [ALC269_LIFEBOOK] = "lifebook",
14976 [ALC269_AUTO] = "auto",
Kailang Yangf6a92242007-12-13 16:52:54 +010014977};
14978
14979static struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014980 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014981 SND_PCI_QUIRK(0x1025, 0x047c, "ACER ZGA", ALC271_ACER),
Kailang Yangf53281e2008-07-18 12:36:43 +020014982 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
Kailang Yang84898e82010-02-04 14:16:14 +010014983 ALC269_AMIC),
14984 SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC),
14985 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC),
14986 SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC),
14987 SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC),
14988 SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC),
14989 SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC),
14990 SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC),
14991 SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC),
14992 SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC),
14993 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82Jv", ALC269_AMIC),
14994 SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC),
14995 SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC),
14996 SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC),
14997 SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC),
14998 SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC),
14999 SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC),
15000 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC),
15001 SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC),
15002 SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC),
15003 SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC),
15004 SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC),
15005 SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC),
15006 SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC),
15007 SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC),
15008 SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC),
15009 SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC),
15010 SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC),
15011 SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC),
15012 SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC),
15013 SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC),
15014 SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC),
15015 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC),
15016 SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC),
15017 SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC),
15018 SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC),
15019 SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC),
Kailang Yangf53281e2008-07-18 12:36:43 +020015020 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
Kailang Yang84898e82010-02-04 14:16:14 +010015021 ALC269_DMIC),
Kailang Yang60db6b52008-08-26 13:13:00 +020015022 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
Kailang Yang84898e82010-02-04 14:16:14 +010015023 ALC269_DMIC),
15024 SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC),
15025 SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC),
Takashi Iwaiff818c22010-04-12 08:59:25 +020015026 SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_AUTO),
Tony Vroon64154832008-11-06 15:08:49 +000015027 SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
Kailang Yang61c2d2b2010-02-25 08:49:06 +010015028 SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC),
15029 SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
15030 SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_AMIC),
15031 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_AMIC),
15032 SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_DMIC),
15033 SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_DMIC),
Kailang Yangf6a92242007-12-13 16:52:54 +010015034 {}
15035};
15036
15037static struct alc_config_preset alc269_presets[] = {
15038 [ALC269_BASIC] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015039 .mixers = { alc269_base_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010015040 .init_verbs = { alc269_init_verbs },
15041 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15042 .dac_nids = alc269_dac_nids,
15043 .hp_nid = 0x03,
15044 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15045 .channel_mode = alc269_modes,
15046 .input_mux = &alc269_capture_source,
15047 },
Kailang Yang60db6b52008-08-26 13:13:00 +020015048 [ALC269_QUANTA_FL1] = {
15049 .mixers = { alc269_quanta_fl1_mixer },
15050 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
15051 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15052 .dac_nids = alc269_dac_nids,
15053 .hp_nid = 0x03,
15054 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15055 .channel_mode = alc269_modes,
15056 .input_mux = &alc269_capture_source,
15057 .unsol_event = alc269_quanta_fl1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020015058 .setup = alc269_quanta_fl1_setup,
Kailang Yang60db6b52008-08-26 13:13:00 +020015059 .init_hook = alc269_quanta_fl1_init_hook,
15060 },
Kailang Yang84898e82010-02-04 14:16:14 +010015061 [ALC269_AMIC] = {
15062 .mixers = { alc269_laptop_mixer },
15063 .cap_mixer = alc269_laptop_analog_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020015064 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010015065 alc269_laptop_amic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020015066 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15067 .dac_nids = alc269_dac_nids,
15068 .hp_nid = 0x03,
15069 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15070 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010015071 .unsol_event = alc269_laptop_unsol_event,
15072 .setup = alc269_laptop_amic_setup,
15073 .init_hook = alc269_laptop_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020015074 },
Kailang Yang84898e82010-02-04 14:16:14 +010015075 [ALC269_DMIC] = {
15076 .mixers = { alc269_laptop_mixer },
15077 .cap_mixer = alc269_laptop_digital_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020015078 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010015079 alc269_laptop_dmic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020015080 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15081 .dac_nids = alc269_dac_nids,
15082 .hp_nid = 0x03,
15083 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15084 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010015085 .unsol_event = alc269_laptop_unsol_event,
15086 .setup = alc269_laptop_dmic_setup,
15087 .init_hook = alc269_laptop_inithook,
15088 },
15089 [ALC269VB_AMIC] = {
15090 .mixers = { alc269vb_laptop_mixer },
15091 .cap_mixer = alc269vb_laptop_analog_capture_mixer,
15092 .init_verbs = { alc269vb_init_verbs,
15093 alc269vb_laptop_amic_init_verbs },
15094 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15095 .dac_nids = alc269_dac_nids,
15096 .hp_nid = 0x03,
15097 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15098 .channel_mode = alc269_modes,
15099 .unsol_event = alc269_laptop_unsol_event,
Kailang Yang226b1ec2010-04-09 11:01:20 +020015100 .setup = alc269vb_laptop_amic_setup,
Kailang Yang84898e82010-02-04 14:16:14 +010015101 .init_hook = alc269_laptop_inithook,
15102 },
15103 [ALC269VB_DMIC] = {
15104 .mixers = { alc269vb_laptop_mixer },
15105 .cap_mixer = alc269vb_laptop_digital_capture_mixer,
15106 .init_verbs = { alc269vb_init_verbs,
15107 alc269vb_laptop_dmic_init_verbs },
15108 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15109 .dac_nids = alc269_dac_nids,
15110 .hp_nid = 0x03,
15111 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15112 .channel_mode = alc269_modes,
15113 .unsol_event = alc269_laptop_unsol_event,
15114 .setup = alc269vb_laptop_dmic_setup,
15115 .init_hook = alc269_laptop_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020015116 },
Takashi Iwai26f5df22008-11-03 17:39:46 +010015117 [ALC269_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010015118 .mixers = { alc269_fujitsu_mixer },
Kailang Yang84898e82010-02-04 14:16:14 +010015119 .cap_mixer = alc269_laptop_digital_capture_mixer,
Takashi Iwai26f5df22008-11-03 17:39:46 +010015120 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010015121 alc269_laptop_dmic_init_verbs },
Takashi Iwai26f5df22008-11-03 17:39:46 +010015122 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15123 .dac_nids = alc269_dac_nids,
15124 .hp_nid = 0x03,
15125 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15126 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010015127 .unsol_event = alc269_laptop_unsol_event,
15128 .setup = alc269_laptop_dmic_setup,
15129 .init_hook = alc269_laptop_inithook,
Takashi Iwai26f5df22008-11-03 17:39:46 +010015130 },
Tony Vroon64154832008-11-06 15:08:49 +000015131 [ALC269_LIFEBOOK] = {
15132 .mixers = { alc269_lifebook_mixer },
15133 .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
15134 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15135 .dac_nids = alc269_dac_nids,
15136 .hp_nid = 0x03,
15137 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15138 .channel_mode = alc269_modes,
15139 .input_mux = &alc269_capture_source,
15140 .unsol_event = alc269_lifebook_unsol_event,
15141 .init_hook = alc269_lifebook_init_hook,
15142 },
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020015143 [ALC271_ACER] = {
15144 .mixers = { alc269_asus_mixer },
15145 .cap_mixer = alc269vb_laptop_digital_capture_mixer,
15146 .init_verbs = { alc269_init_verbs, alc271_acer_dmic_verbs },
15147 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15148 .dac_nids = alc269_dac_nids,
15149 .adc_nids = alc262_dmic_adc_nids,
15150 .num_adc_nids = ARRAY_SIZE(alc262_dmic_adc_nids),
15151 .capsrc_nids = alc262_dmic_capsrc_nids,
15152 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15153 .channel_mode = alc269_modes,
15154 .input_mux = &alc269_capture_source,
15155 .dig_out_nid = ALC880_DIGOUT_NID,
15156 .unsol_event = alc_sku_unsol_event,
15157 .setup = alc269vb_laptop_dmic_setup,
15158 .init_hook = alc_inithook,
15159 },
Kailang Yangf6a92242007-12-13 16:52:54 +010015160};
15161
Kailang Yang977ddd62010-09-15 10:02:29 +020015162static int alc269_fill_coef(struct hda_codec *codec)
15163{
15164 int val;
15165
15166 if ((alc_read_coef_idx(codec, 0) & 0x00ff) < 0x015) {
15167 alc_write_coef_idx(codec, 0xf, 0x960b);
15168 alc_write_coef_idx(codec, 0xe, 0x8817);
15169 }
15170
15171 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x016) {
15172 alc_write_coef_idx(codec, 0xf, 0x960b);
15173 alc_write_coef_idx(codec, 0xe, 0x8814);
15174 }
15175
15176 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
15177 val = alc_read_coef_idx(codec, 0x04);
15178 /* Power up output pin */
15179 alc_write_coef_idx(codec, 0x04, val | (1<<11));
15180 }
15181
15182 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
15183 val = alc_read_coef_idx(codec, 0xd);
15184 if ((val & 0x0c00) >> 10 != 0x1) {
15185 /* Capless ramp up clock control */
15186 alc_write_coef_idx(codec, 0xd, val | 1<<10);
15187 }
15188 val = alc_read_coef_idx(codec, 0x17);
15189 if ((val & 0x01c0) >> 6 != 0x4) {
15190 /* Class D power on reset */
15191 alc_write_coef_idx(codec, 0x17, val | 1<<7);
15192 }
15193 }
15194 return 0;
15195}
15196
Kailang Yangf6a92242007-12-13 16:52:54 +010015197static int patch_alc269(struct hda_codec *codec)
15198{
15199 struct alc_spec *spec;
Kailang Yang48c88e82010-11-23 08:56:16 +010015200 int board_config, coef;
Kailang Yangf6a92242007-12-13 16:52:54 +010015201 int err;
15202
15203 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
15204 if (spec == NULL)
15205 return -ENOMEM;
15206
15207 codec->spec = spec;
15208
Kailang Yangda00c242010-03-19 11:23:45 +010015209 alc_auto_parse_customize_define(codec);
15210
Kailang Yangc793bec2010-12-21 09:14:13 +010015211 if (codec->vendor_id == 0x10ec0269) {
15212 coef = alc_read_coef_idx(codec, 0);
15213 if ((coef & 0x00f0) == 0x0010) {
15214 if (codec->bus->pci->subsystem_vendor == 0x1025 &&
15215 spec->cdefine.platform_type == 1) {
15216 alc_codec_rename(codec, "ALC271X");
15217 spec->codec_variant = ALC269_TYPE_ALC271X;
15218 } else if ((coef & 0xf000) == 0x1000) {
15219 spec->codec_variant = ALC269_TYPE_ALC270;
15220 } else if ((coef & 0xf000) == 0x2000) {
15221 alc_codec_rename(codec, "ALC259");
15222 spec->codec_variant = ALC269_TYPE_ALC259;
15223 } else if ((coef & 0xf000) == 0x3000) {
15224 alc_codec_rename(codec, "ALC258");
15225 spec->codec_variant = ALC269_TYPE_ALC258;
15226 } else {
15227 alc_codec_rename(codec, "ALC269VB");
15228 spec->codec_variant = ALC269_TYPE_ALC269VB;
15229 }
15230 } else
15231 alc_fix_pll_init(codec, 0x20, 0x04, 15);
15232 alc269_fill_coef(codec);
15233 }
Kailang Yang977ddd62010-09-15 10:02:29 +020015234
Kailang Yangf6a92242007-12-13 16:52:54 +010015235 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
15236 alc269_models,
15237 alc269_cfg_tbl);
15238
15239 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020015240 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
15241 codec->chip_name);
Kailang Yangf6a92242007-12-13 16:52:54 +010015242 board_config = ALC269_AUTO;
15243 }
15244
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010015245 if (board_config == ALC269_AUTO) {
15246 alc_pick_fixup(codec, NULL, alc269_fixup_tbl, alc269_fixups);
15247 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
15248 }
Takashi Iwaiff818c22010-04-12 08:59:25 +020015249
Kailang Yangf6a92242007-12-13 16:52:54 +010015250 if (board_config == ALC269_AUTO) {
15251 /* automatic parse from the BIOS config */
15252 err = alc269_parse_auto_config(codec);
15253 if (err < 0) {
15254 alc_free(codec);
15255 return err;
15256 } else if (!err) {
15257 printk(KERN_INFO
15258 "hda_codec: Cannot set up configuration "
15259 "from BIOS. Using base mode...\n");
15260 board_config = ALC269_BASIC;
15261 }
15262 }
15263
Takashi Iwaidc1eae22010-07-29 15:30:02 +020015264 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020015265 err = snd_hda_attach_beep_device(codec, 0x1);
15266 if (err < 0) {
15267 alc_free(codec);
15268 return err;
15269 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090015270 }
15271
Kailang Yangf6a92242007-12-13 16:52:54 +010015272 if (board_config != ALC269_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020015273 setup_preset(codec, &alc269_presets[board_config]);
Kailang Yangf6a92242007-12-13 16:52:54 +010015274
Kailang Yang84898e82010-02-04 14:16:14 +010015275 if (board_config == ALC269_QUANTA_FL1) {
Takashi Iwaif03d3112009-03-05 14:18:16 +010015276 /* Due to a hardware problem on Lenovo Ideadpad, we need to
15277 * fix the sample rate of analog I/O to 44.1kHz
15278 */
15279 spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
15280 spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
Takashi Iwai840b64c2010-07-13 22:49:01 +020015281 } else if (spec->dual_adc_switch) {
15282 spec->stream_analog_playback = &alc269_pcm_analog_playback;
15283 /* switch ADC dynamically */
15284 spec->stream_analog_capture = &dualmic_pcm_analog_capture;
Takashi Iwaif03d3112009-03-05 14:18:16 +010015285 } else {
15286 spec->stream_analog_playback = &alc269_pcm_analog_playback;
15287 spec->stream_analog_capture = &alc269_pcm_analog_capture;
15288 }
Kailang Yangf6a92242007-12-13 16:52:54 +010015289 spec->stream_digital_playback = &alc269_pcm_digital_playback;
15290 spec->stream_digital_capture = &alc269_pcm_digital_capture;
15291
Takashi Iwai66946352010-03-29 17:21:45 +020015292 if (!spec->adc_nids) { /* wasn't filled automatically? use default */
Kailang Yang1657cbd2010-11-23 08:53:32 +010015293 if (spec->codec_variant == ALC269_TYPE_NORMAL) {
Takashi Iwai66946352010-03-29 17:21:45 +020015294 spec->adc_nids = alc269_adc_nids;
15295 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
15296 spec->capsrc_nids = alc269_capsrc_nids;
15297 } else {
15298 spec->adc_nids = alc269vb_adc_nids;
15299 spec->num_adc_nids = ARRAY_SIZE(alc269vb_adc_nids);
15300 spec->capsrc_nids = alc269vb_capsrc_nids;
15301 }
Kailang Yang84898e82010-02-04 14:16:14 +010015302 }
15303
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015304 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020015305 set_capture_mixer(codec);
Takashi Iwaidc1eae22010-07-29 15:30:02 +020015306 if (has_cdefine_beep(codec))
Kailang Yangda00c242010-03-19 11:23:45 +010015307 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Kailang Yangf6a92242007-12-13 16:52:54 +010015308
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010015309 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwaiff818c22010-04-12 08:59:25 +020015310
Takashi Iwai100d5eb2009-08-10 11:55:51 +020015311 spec->vmaster_nid = 0x02;
15312
Kailang Yangf6a92242007-12-13 16:52:54 +010015313 codec->patch_ops = alc_patch_ops;
Kailang Yang977ddd62010-09-15 10:02:29 +020015314#ifdef CONFIG_SND_HDA_POWER_SAVE
15315 codec->patch_ops.suspend = alc269_suspend;
15316#endif
15317#ifdef SND_HDA_NEEDS_RESUME
15318 codec->patch_ops.resume = alc269_resume;
15319#endif
Kailang Yangf6a92242007-12-13 16:52:54 +010015320 if (board_config == ALC269_AUTO)
15321 spec->init_hook = alc269_auto_init;
Kailang Yangbf1b0222010-10-21 08:49:56 +020015322
15323 alc_init_jacks(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010015324#ifdef CONFIG_SND_HDA_POWER_SAVE
15325 if (!spec->loopback.amplist)
15326 spec->loopback.amplist = alc269_loopbacks;
Takashi Iwaiad358792010-03-30 18:00:59 +020015327 if (alc269_mic2_for_mute_led(codec))
15328 codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps;
Kailang Yangf6a92242007-12-13 16:52:54 +010015329#endif
15330
15331 return 0;
15332}
15333
15334/*
Kailang Yangdf694da2005-12-05 19:42:22 +010015335 * ALC861 channel source setting (2/6 channel selection for 3-stack)
15336 */
15337
15338/*
15339 * set the path ways for 2 channel output
15340 * need to set the codec line out and mic 1 pin widgets to inputs
15341 */
15342static struct hda_verb alc861_threestack_ch2_init[] = {
15343 /* set pin widget 1Ah (line in) for input */
15344 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015345 /* set pin widget 18h (mic1/2) for input, for mic also enable
15346 * the vref
15347 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015348 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15349
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015350 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
15351#if 0
15352 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
15353 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
15354#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010015355 { } /* end */
15356};
15357/*
15358 * 6ch mode
15359 * need to set the codec line out and mic 1 pin widgets to outputs
15360 */
15361static struct hda_verb alc861_threestack_ch6_init[] = {
15362 /* set pin widget 1Ah (line in) for output (Back Surround)*/
15363 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15364 /* set pin widget 18h (mic1) for output (CLFE)*/
15365 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15366
15367 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015368 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015369
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015370 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
15371#if 0
15372 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
15373 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
15374#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010015375 { } /* end */
15376};
15377
15378static struct hda_channel_mode alc861_threestack_modes[2] = {
15379 { 2, alc861_threestack_ch2_init },
15380 { 6, alc861_threestack_ch6_init },
15381};
Takashi Iwai22309c32006-08-09 16:57:28 +020015382/* Set mic1 as input and unmute the mixer */
15383static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
15384 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15385 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
15386 { } /* end */
15387};
15388/* Set mic1 as output and mute mixer */
15389static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
15390 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15391 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
15392 { } /* end */
15393};
15394
15395static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
15396 { 2, alc861_uniwill_m31_ch2_init },
15397 { 4, alc861_uniwill_m31_ch4_init },
15398};
Kailang Yangdf694da2005-12-05 19:42:22 +010015399
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015400/* Set mic1 and line-in as input and unmute the mixer */
15401static struct hda_verb alc861_asus_ch2_init[] = {
15402 /* set pin widget 1Ah (line in) for input */
15403 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015404 /* set pin widget 18h (mic1/2) for input, for mic also enable
15405 * the vref
15406 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015407 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15408
15409 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
15410#if 0
15411 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
15412 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
15413#endif
15414 { } /* end */
15415};
15416/* Set mic1 nad line-in as output and mute mixer */
15417static struct hda_verb alc861_asus_ch6_init[] = {
15418 /* set pin widget 1Ah (line in) for output (Back Surround)*/
15419 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15420 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
15421 /* set pin widget 18h (mic1) for output (CLFE)*/
15422 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15423 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
15424 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
15425 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
15426
15427 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
15428#if 0
15429 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
15430 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
15431#endif
15432 { } /* end */
15433};
15434
15435static struct hda_channel_mode alc861_asus_modes[2] = {
15436 { 2, alc861_asus_ch2_init },
15437 { 6, alc861_asus_ch6_init },
15438};
15439
Kailang Yangdf694da2005-12-05 19:42:22 +010015440/* patch-ALC861 */
15441
15442static struct snd_kcontrol_new alc861_base_mixer[] = {
15443 /* output mixer control */
15444 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15445 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15446 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15447 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15448 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
15449
15450 /*Input mixer control */
15451 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15452 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
15453 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15454 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15455 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15456 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15457 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15458 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15459 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
15460 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015461
Kailang Yangdf694da2005-12-05 19:42:22 +010015462 { } /* end */
15463};
15464
15465static struct snd_kcontrol_new alc861_3ST_mixer[] = {
15466 /* output mixer control */
15467 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15468 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15469 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15470 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15471 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
15472
15473 /* Input mixer control */
15474 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15475 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
15476 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15477 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15478 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15479 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15480 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15481 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15482 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
15483 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015484
Kailang Yangdf694da2005-12-05 19:42:22 +010015485 {
15486 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15487 .name = "Channel Mode",
15488 .info = alc_ch_mode_info,
15489 .get = alc_ch_mode_get,
15490 .put = alc_ch_mode_put,
15491 .private_value = ARRAY_SIZE(alc861_threestack_modes),
15492 },
15493 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015494};
15495
Takashi Iwaid1d985f2006-11-23 19:27:12 +010015496static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015497 /* output mixer control */
15498 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15499 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15500 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020015501
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015502 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015503};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015504
Takashi Iwai22309c32006-08-09 16:57:28 +020015505static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
15506 /* output mixer control */
15507 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15508 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15509 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15510 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15511 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
15512
15513 /* Input mixer control */
15514 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15515 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
15516 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15517 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15518 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15519 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15520 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15521 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15522 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
15523 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015524
Takashi Iwai22309c32006-08-09 16:57:28 +020015525 {
15526 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15527 .name = "Channel Mode",
15528 .info = alc_ch_mode_info,
15529 .get = alc_ch_mode_get,
15530 .put = alc_ch_mode_put,
15531 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
15532 },
15533 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015534};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015535
15536static struct snd_kcontrol_new alc861_asus_mixer[] = {
15537 /* output mixer control */
15538 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15539 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15540 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15541 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15542 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
15543
15544 /* Input mixer control */
15545 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15546 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
15547 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15548 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15549 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15550 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15551 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15552 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15553 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015554 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
15555
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015556 {
15557 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15558 .name = "Channel Mode",
15559 .info = alc_ch_mode_info,
15560 .get = alc_ch_mode_get,
15561 .put = alc_ch_mode_put,
15562 .private_value = ARRAY_SIZE(alc861_asus_modes),
15563 },
15564 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015565};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015566
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015567/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010015568static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015569 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15570 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015571 { }
15572};
15573
Kailang Yangdf694da2005-12-05 19:42:22 +010015574/*
15575 * generic initialization of ADC, input mixers and output mixers
15576 */
15577static struct hda_verb alc861_base_init_verbs[] = {
15578 /*
15579 * Unmute ADC0 and set the default input to mic-in
15580 */
15581 /* port-A for surround (rear panel) */
15582 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15583 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
15584 /* port-B for mic-in (rear panel) with vref */
15585 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15586 /* port-C for line-in (rear panel) */
15587 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15588 /* port-D for Front */
15589 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15590 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15591 /* port-E for HP out (front panel) */
15592 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
15593 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015594 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015595 /* port-F for mic-in (front panel) with vref */
15596 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15597 /* port-G for CLFE (rear panel) */
15598 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15599 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
15600 /* port-H for side (rear panel) */
15601 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15602 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
15603 /* CD-in */
15604 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15605 /* route front mic to ADC1*/
15606 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15607 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015608
Kailang Yangdf694da2005-12-05 19:42:22 +010015609 /* Unmute DAC0~3 & spdif out*/
15610 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15611 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15612 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15613 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15614 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015615
Kailang Yangdf694da2005-12-05 19:42:22 +010015616 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15617 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15618 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15619 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15620 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015621
Kailang Yangdf694da2005-12-05 19:42:22 +010015622 /* Unmute Stereo Mixer 15 */
15623 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15624 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15625 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015626 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015627
15628 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15629 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15630 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15631 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15632 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15633 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15634 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15635 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015636 /* hp used DAC 3 (Front) */
15637 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015638 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15639
15640 { }
15641};
15642
15643static struct hda_verb alc861_threestack_init_verbs[] = {
15644 /*
15645 * Unmute ADC0 and set the default input to mic-in
15646 */
15647 /* port-A for surround (rear panel) */
15648 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15649 /* port-B for mic-in (rear panel) with vref */
15650 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15651 /* port-C for line-in (rear panel) */
15652 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15653 /* port-D for Front */
15654 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15655 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15656 /* port-E for HP out (front panel) */
15657 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
15658 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015659 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015660 /* port-F for mic-in (front panel) with vref */
15661 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15662 /* port-G for CLFE (rear panel) */
15663 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15664 /* port-H for side (rear panel) */
15665 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15666 /* CD-in */
15667 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15668 /* route front mic to ADC1*/
15669 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15670 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15671 /* Unmute DAC0~3 & spdif out*/
15672 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15673 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15674 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15675 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15676 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015677
Kailang Yangdf694da2005-12-05 19:42:22 +010015678 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15679 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15680 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15681 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15682 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015683
Kailang Yangdf694da2005-12-05 19:42:22 +010015684 /* Unmute Stereo Mixer 15 */
15685 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15686 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15687 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015688 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015689
15690 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15691 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15692 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15693 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15694 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15695 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15696 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15697 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015698 /* hp used DAC 3 (Front) */
15699 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015700 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15701 { }
15702};
Takashi Iwai22309c32006-08-09 16:57:28 +020015703
15704static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
15705 /*
15706 * Unmute ADC0 and set the default input to mic-in
15707 */
15708 /* port-A for surround (rear panel) */
15709 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15710 /* port-B for mic-in (rear panel) with vref */
15711 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15712 /* port-C for line-in (rear panel) */
15713 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15714 /* port-D for Front */
15715 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15716 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15717 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015718 /* this has to be set to VREF80 */
15719 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015720 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015721 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015722 /* port-F for mic-in (front panel) with vref */
15723 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15724 /* port-G for CLFE (rear panel) */
15725 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15726 /* port-H for side (rear panel) */
15727 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15728 /* CD-in */
15729 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15730 /* route front mic to ADC1*/
15731 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15732 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15733 /* Unmute DAC0~3 & spdif out*/
15734 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15735 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15736 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15737 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15738 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015739
Takashi Iwai22309c32006-08-09 16:57:28 +020015740 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15741 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15742 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15743 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15744 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015745
Takashi Iwai22309c32006-08-09 16:57:28 +020015746 /* Unmute Stereo Mixer 15 */
15747 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15748 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15749 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015750 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020015751
15752 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15753 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15754 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15755 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15756 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15757 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15758 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15759 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015760 /* hp used DAC 3 (Front) */
15761 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020015762 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15763 { }
15764};
15765
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015766static struct hda_verb alc861_asus_init_verbs[] = {
15767 /*
15768 * Unmute ADC0 and set the default input to mic-in
15769 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015770 /* port-A for surround (rear panel)
15771 * according to codec#0 this is the HP jack
15772 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015773 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
15774 /* route front PCM to HP */
15775 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
15776 /* port-B for mic-in (rear panel) with vref */
15777 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15778 /* port-C for line-in (rear panel) */
15779 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15780 /* port-D for Front */
15781 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15782 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15783 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015784 /* this has to be set to VREF80 */
15785 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015786 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015787 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015788 /* port-F for mic-in (front panel) with vref */
15789 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15790 /* port-G for CLFE (rear panel) */
15791 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15792 /* port-H for side (rear panel) */
15793 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15794 /* CD-in */
15795 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15796 /* route front mic to ADC1*/
15797 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15798 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15799 /* Unmute DAC0~3 & spdif out*/
15800 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15801 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15802 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15803 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15804 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15805 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15806 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15807 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15808 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15809 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015810
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015811 /* Unmute Stereo Mixer 15 */
15812 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15813 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15814 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015815 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015816
15817 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15818 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15819 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15820 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15821 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15822 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15823 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15824 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015825 /* hp used DAC 3 (Front) */
15826 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015827 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15828 { }
15829};
15830
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015831/* additional init verbs for ASUS laptops */
15832static struct hda_verb alc861_asus_laptop_init_verbs[] = {
15833 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
15834 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
15835 { }
15836};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015837
Kailang Yangdf694da2005-12-05 19:42:22 +010015838/*
15839 * generic initialization of ADC, input mixers and output mixers
15840 */
15841static struct hda_verb alc861_auto_init_verbs[] = {
15842 /*
15843 * Unmute ADC0 and set the default input to mic-in
15844 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015845 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010015846 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015847
Kailang Yangdf694da2005-12-05 19:42:22 +010015848 /* Unmute DAC0~3 & spdif out*/
15849 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15850 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15851 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15852 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15853 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015854
Kailang Yangdf694da2005-12-05 19:42:22 +010015855 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15856 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15857 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15858 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15859 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015860
Kailang Yangdf694da2005-12-05 19:42:22 +010015861 /* Unmute Stereo Mixer 15 */
15862 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15863 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15864 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15865 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
15866
Takashi Iwai1c209302009-07-22 15:17:45 +020015867 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15868 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15869 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15870 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15871 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15872 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15873 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15874 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015875
15876 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15877 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020015878 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15879 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015880 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15881 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020015882 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15883 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015884
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015885 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015886
15887 { }
15888};
15889
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015890static struct hda_verb alc861_toshiba_init_verbs[] = {
15891 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015892
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015893 { }
15894};
15895
15896/* toggle speaker-output according to the hp-jack state */
15897static void alc861_toshiba_automute(struct hda_codec *codec)
15898{
Wu Fengguang864f92b2009-11-18 12:38:02 +080015899 unsigned int present = snd_hda_jack_detect(codec, 0x0f);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015900
Takashi Iwai47fd8302007-08-10 17:11:07 +020015901 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
15902 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
15903 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
15904 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015905}
15906
15907static void alc861_toshiba_unsol_event(struct hda_codec *codec,
15908 unsigned int res)
15909{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015910 if ((res >> 26) == ALC880_HP_EVENT)
15911 alc861_toshiba_automute(codec);
15912}
15913
Sasha Alexandrdef319f2009-06-16 16:00:15 -040015914/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015915#define alc861_pcm_analog_playback alc880_pcm_analog_playback
15916#define alc861_pcm_analog_capture alc880_pcm_analog_capture
15917#define alc861_pcm_digital_playback alc880_pcm_digital_playback
15918#define alc861_pcm_digital_capture alc880_pcm_digital_capture
15919
15920
15921#define ALC861_DIGOUT_NID 0x07
15922
15923static struct hda_channel_mode alc861_8ch_modes[1] = {
15924 { 8, NULL }
15925};
15926
15927static hda_nid_t alc861_dac_nids[4] = {
15928 /* front, surround, clfe, side */
15929 0x03, 0x06, 0x05, 0x04
15930};
15931
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015932static hda_nid_t alc660_dac_nids[3] = {
15933 /* front, clfe, surround */
15934 0x03, 0x05, 0x06
15935};
15936
Kailang Yangdf694da2005-12-05 19:42:22 +010015937static hda_nid_t alc861_adc_nids[1] = {
15938 /* ADC0-2 */
15939 0x08,
15940};
15941
15942static struct hda_input_mux alc861_capture_source = {
15943 .num_items = 5,
15944 .items = {
15945 { "Mic", 0x0 },
15946 { "Front Mic", 0x3 },
15947 { "Line", 0x1 },
15948 { "CD", 0x4 },
15949 { "Mixer", 0x5 },
15950 },
15951};
15952
Takashi Iwai1c209302009-07-22 15:17:45 +020015953static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
15954{
15955 struct alc_spec *spec = codec->spec;
15956 hda_nid_t mix, srcs[5];
15957 int i, j, num;
15958
15959 if (snd_hda_get_connections(codec, pin, &mix, 1) != 1)
15960 return 0;
15961 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
15962 if (num < 0)
15963 return 0;
15964 for (i = 0; i < num; i++) {
15965 unsigned int type;
Takashi Iwaia22d5432009-07-27 12:54:26 +020015966 type = get_wcaps_type(get_wcaps(codec, srcs[i]));
Takashi Iwai1c209302009-07-22 15:17:45 +020015967 if (type != AC_WID_AUD_OUT)
15968 continue;
15969 for (j = 0; j < spec->multiout.num_dacs; j++)
15970 if (spec->multiout.dac_nids[j] == srcs[i])
15971 break;
15972 if (j >= spec->multiout.num_dacs)
15973 return srcs[i];
15974 }
15975 return 0;
15976}
15977
Kailang Yangdf694da2005-12-05 19:42:22 +010015978/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwai1c209302009-07-22 15:17:45 +020015979static int alc861_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015980 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010015981{
Takashi Iwai1c209302009-07-22 15:17:45 +020015982 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015983 int i;
Takashi Iwai1c209302009-07-22 15:17:45 +020015984 hda_nid_t nid, dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010015985
15986 spec->multiout.dac_nids = spec->private_dac_nids;
15987 for (i = 0; i < cfg->line_outs; i++) {
15988 nid = cfg->line_out_pins[i];
Takashi Iwai1c209302009-07-22 15:17:45 +020015989 dac = alc861_look_for_dac(codec, nid);
15990 if (!dac)
15991 continue;
15992 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010015993 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015994 return 0;
15995}
15996
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010015997static int __alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
15998 hda_nid_t nid, int idx, unsigned int chs)
Kailang Yangdf694da2005-12-05 19:42:22 +010015999{
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016000 return __add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx, idx,
Takashi Iwai1c209302009-07-22 15:17:45 +020016001 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
16002}
16003
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016004#define alc861_create_out_sw(codec, pfx, nid, chs) \
16005 __alc861_create_out_sw(codec, pfx, nid, 0, chs)
16006
Takashi Iwai1c209302009-07-22 15:17:45 +020016007/* add playback controls from the parsed DAC table */
16008static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
16009 const struct auto_pin_cfg *cfg)
16010{
16011 struct alc_spec *spec = codec->spec;
Takashi Iwaiea734962011-01-17 11:29:34 +010016012 static const char * const chname[4] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016013 "Front", "Surround", NULL /*CLFE*/, "Side"
16014 };
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016015 const char *pfx = alc_get_line_out_pfx(cfg, true);
Kailang Yangdf694da2005-12-05 19:42:22 +010016016 hda_nid_t nid;
Takashi Iwai1c209302009-07-22 15:17:45 +020016017 int i, err;
16018
Kailang Yangdf694da2005-12-05 19:42:22 +010016019 for (i = 0; i < cfg->line_outs; i++) {
16020 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016021 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010016022 continue;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016023 if (!pfx && i == 2) {
Kailang Yangdf694da2005-12-05 19:42:22 +010016024 /* Center/LFE */
Takashi Iwai1c209302009-07-22 15:17:45 +020016025 err = alc861_create_out_sw(codec, "Center", nid, 1);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016026 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010016027 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020016028 err = alc861_create_out_sw(codec, "LFE", nid, 2);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016029 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010016030 return err;
16031 } else {
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016032 const char *name = pfx;
16033 if (!name)
16034 name = chname[i];
16035 err = __alc861_create_out_sw(codec, name, nid, i, 3);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016036 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010016037 return err;
16038 }
16039 }
16040 return 0;
16041}
16042
Takashi Iwai1c209302009-07-22 15:17:45 +020016043static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010016044{
Takashi Iwai1c209302009-07-22 15:17:45 +020016045 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010016046 int err;
16047 hda_nid_t nid;
16048
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016049 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010016050 return 0;
16051
16052 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
Takashi Iwai1c209302009-07-22 15:17:45 +020016053 nid = alc861_look_for_dac(codec, pin);
16054 if (nid) {
16055 err = alc861_create_out_sw(codec, "Headphone", nid, 3);
16056 if (err < 0)
16057 return err;
16058 spec->multiout.hp_nid = nid;
16059 }
Kailang Yangdf694da2005-12-05 19:42:22 +010016060 }
16061 return 0;
16062}
16063
16064/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020016065static int alc861_auto_create_input_ctls(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016066 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010016067{
Takashi Iwai05f5f472009-08-25 13:10:18 +020016068 return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x08, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010016069}
16070
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016071static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
16072 hda_nid_t nid,
Takashi Iwai1c209302009-07-22 15:17:45 +020016073 int pin_type, hda_nid_t dac)
Kailang Yangdf694da2005-12-05 19:42:22 +010016074{
Takashi Iwai1c209302009-07-22 15:17:45 +020016075 hda_nid_t mix, srcs[5];
16076 int i, num;
16077
Jacek Luczak564c5be2008-05-03 18:41:23 +020016078 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
16079 pin_type);
Takashi Iwai1c209302009-07-22 15:17:45 +020016080 snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Jacek Luczak564c5be2008-05-03 18:41:23 +020016081 AMP_OUT_UNMUTE);
Takashi Iwai1c209302009-07-22 15:17:45 +020016082 if (snd_hda_get_connections(codec, nid, &mix, 1) != 1)
16083 return;
16084 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
16085 if (num < 0)
16086 return;
16087 for (i = 0; i < num; i++) {
16088 unsigned int mute;
16089 if (srcs[i] == dac || srcs[i] == 0x15)
16090 mute = AMP_IN_UNMUTE(i);
16091 else
16092 mute = AMP_IN_MUTE(i);
16093 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
16094 mute);
16095 }
Kailang Yangdf694da2005-12-05 19:42:22 +010016096}
16097
16098static void alc861_auto_init_multi_out(struct hda_codec *codec)
16099{
16100 struct alc_spec *spec = codec->spec;
16101 int i;
16102
16103 for (i = 0; i < spec->autocfg.line_outs; i++) {
16104 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016105 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010016106 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016107 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016108 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010016109 }
16110}
16111
16112static void alc861_auto_init_hp_out(struct hda_codec *codec)
16113{
16114 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010016115
Takashi Iwai15870f02009-10-05 08:25:13 +020016116 if (spec->autocfg.hp_outs)
16117 alc861_auto_set_output_and_unmute(codec,
16118 spec->autocfg.hp_pins[0],
16119 PIN_HP,
Takashi Iwai1c209302009-07-22 15:17:45 +020016120 spec->multiout.hp_nid);
Takashi Iwai15870f02009-10-05 08:25:13 +020016121 if (spec->autocfg.speaker_outs)
16122 alc861_auto_set_output_and_unmute(codec,
16123 spec->autocfg.speaker_pins[0],
16124 PIN_OUT,
Takashi Iwai1c209302009-07-22 15:17:45 +020016125 spec->multiout.dac_nids[0]);
Kailang Yangdf694da2005-12-05 19:42:22 +010016126}
16127
16128static void alc861_auto_init_analog_input(struct hda_codec *codec)
16129{
16130 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020016131 struct auto_pin_cfg *cfg = &spec->autocfg;
Kailang Yangdf694da2005-12-05 19:42:22 +010016132 int i;
16133
Takashi Iwai66ceeb62010-08-30 13:05:52 +020016134 for (i = 0; i < cfg->num_inputs; i++) {
16135 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai23f0c042009-02-26 13:03:58 +010016136 if (nid >= 0x0c && nid <= 0x11)
Takashi Iwai30ea0982010-09-16 18:47:56 +020016137 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Kailang Yangdf694da2005-12-05 19:42:22 +010016138 }
16139}
16140
16141/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016142/* return 1 if successful, 0 if the proper config is not found,
16143 * or a negative error code
16144 */
Kailang Yangdf694da2005-12-05 19:42:22 +010016145static int alc861_parse_auto_config(struct hda_codec *codec)
16146{
16147 struct alc_spec *spec = codec->spec;
16148 int err;
16149 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
16150
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016151 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
16152 alc861_ignore);
16153 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010016154 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016155 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010016156 return 0; /* can't find valid BIOS pin config */
16157
Takashi Iwai1c209302009-07-22 15:17:45 +020016158 err = alc861_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016159 if (err < 0)
16160 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020016161 err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016162 if (err < 0)
16163 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020016164 err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016165 if (err < 0)
16166 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020016167 err = alc861_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016168 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010016169 return err;
16170
16171 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
16172
Takashi Iwai757899a2010-07-30 10:48:14 +020016173 alc_auto_parse_digital(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010016174
Takashi Iwai603c4012008-07-30 15:01:44 +020016175 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010016176 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010016177
Takashi Iwaid88897e2008-10-31 15:01:37 +010016178 add_verb(spec, alc861_auto_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +010016179
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020016180 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020016181 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010016182
16183 spec->adc_nids = alc861_adc_nids;
16184 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016185 set_capture_mixer(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010016186
Kailang Yang6227cdc2010-02-25 08:36:52 +010016187 alc_ssid_check(codec, 0x0e, 0x0f, 0x0b, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020016188
Kailang Yangdf694da2005-12-05 19:42:22 +010016189 return 1;
16190}
16191
Takashi Iwaiae6b8132006-03-03 16:47:17 +010016192/* additional initialization for auto-configuration model */
16193static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010016194{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016195 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010016196 alc861_auto_init_multi_out(codec);
16197 alc861_auto_init_hp_out(codec);
16198 alc861_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020016199 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016200 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020016201 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010016202}
16203
Takashi Iwaicb53c622007-08-10 17:21:45 +020016204#ifdef CONFIG_SND_HDA_POWER_SAVE
16205static struct hda_amp_list alc861_loopbacks[] = {
16206 { 0x15, HDA_INPUT, 0 },
16207 { 0x15, HDA_INPUT, 1 },
16208 { 0x15, HDA_INPUT, 2 },
16209 { 0x15, HDA_INPUT, 3 },
16210 { } /* end */
16211};
16212#endif
16213
Kailang Yangdf694da2005-12-05 19:42:22 +010016214
16215/*
16216 * configuration and preset
16217 */
Takashi Iwaiea734962011-01-17 11:29:34 +010016218static const char * const alc861_models[ALC861_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010016219 [ALC861_3ST] = "3stack",
16220 [ALC660_3ST] = "3stack-660",
16221 [ALC861_3ST_DIG] = "3stack-dig",
16222 [ALC861_6ST_DIG] = "6stack-dig",
16223 [ALC861_UNIWILL_M31] = "uniwill-m31",
16224 [ALC861_TOSHIBA] = "toshiba",
16225 [ALC861_ASUS] = "asus",
16226 [ALC861_ASUS_LAPTOP] = "asus-laptop",
16227 [ALC861_AUTO] = "auto",
16228};
16229
16230static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010016231 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010016232 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
16233 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
16234 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016235 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020016236 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010016237 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020016238 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
16239 * Any other models that need this preset?
16240 */
16241 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020016242 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
16243 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016244 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
16245 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
16246 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
16247 /* FIXME: the below seems conflict */
16248 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
16249 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
16250 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010016251 {}
16252};
16253
16254static struct alc_config_preset alc861_presets[] = {
16255 [ALC861_3ST] = {
16256 .mixers = { alc861_3ST_mixer },
16257 .init_verbs = { alc861_threestack_init_verbs },
16258 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16259 .dac_nids = alc861_dac_nids,
16260 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
16261 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020016262 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010016263 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16264 .adc_nids = alc861_adc_nids,
16265 .input_mux = &alc861_capture_source,
16266 },
16267 [ALC861_3ST_DIG] = {
16268 .mixers = { alc861_base_mixer },
16269 .init_verbs = { alc861_threestack_init_verbs },
16270 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16271 .dac_nids = alc861_dac_nids,
16272 .dig_out_nid = ALC861_DIGOUT_NID,
16273 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
16274 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020016275 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010016276 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16277 .adc_nids = alc861_adc_nids,
16278 .input_mux = &alc861_capture_source,
16279 },
16280 [ALC861_6ST_DIG] = {
16281 .mixers = { alc861_base_mixer },
16282 .init_verbs = { alc861_base_init_verbs },
16283 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16284 .dac_nids = alc861_dac_nids,
16285 .dig_out_nid = ALC861_DIGOUT_NID,
16286 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
16287 .channel_mode = alc861_8ch_modes,
16288 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16289 .adc_nids = alc861_adc_nids,
16290 .input_mux = &alc861_capture_source,
16291 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016292 [ALC660_3ST] = {
16293 .mixers = { alc861_3ST_mixer },
16294 .init_verbs = { alc861_threestack_init_verbs },
16295 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
16296 .dac_nids = alc660_dac_nids,
16297 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
16298 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020016299 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016300 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16301 .adc_nids = alc861_adc_nids,
16302 .input_mux = &alc861_capture_source,
16303 },
Takashi Iwai22309c32006-08-09 16:57:28 +020016304 [ALC861_UNIWILL_M31] = {
16305 .mixers = { alc861_uniwill_m31_mixer },
16306 .init_verbs = { alc861_uniwill_m31_init_verbs },
16307 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16308 .dac_nids = alc861_dac_nids,
16309 .dig_out_nid = ALC861_DIGOUT_NID,
16310 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
16311 .channel_mode = alc861_uniwill_m31_modes,
16312 .need_dac_fix = 1,
16313 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16314 .adc_nids = alc861_adc_nids,
16315 .input_mux = &alc861_capture_source,
16316 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020016317 [ALC861_TOSHIBA] = {
16318 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016319 .init_verbs = { alc861_base_init_verbs,
16320 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020016321 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16322 .dac_nids = alc861_dac_nids,
16323 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
16324 .channel_mode = alc883_3ST_2ch_modes,
16325 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16326 .adc_nids = alc861_adc_nids,
16327 .input_mux = &alc861_capture_source,
16328 .unsol_event = alc861_toshiba_unsol_event,
16329 .init_hook = alc861_toshiba_automute,
16330 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020016331 [ALC861_ASUS] = {
16332 .mixers = { alc861_asus_mixer },
16333 .init_verbs = { alc861_asus_init_verbs },
16334 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16335 .dac_nids = alc861_dac_nids,
16336 .dig_out_nid = ALC861_DIGOUT_NID,
16337 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
16338 .channel_mode = alc861_asus_modes,
16339 .need_dac_fix = 1,
16340 .hp_nid = 0x06,
16341 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16342 .adc_nids = alc861_adc_nids,
16343 .input_mux = &alc861_capture_source,
16344 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010016345 [ALC861_ASUS_LAPTOP] = {
16346 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
16347 .init_verbs = { alc861_asus_init_verbs,
16348 alc861_asus_laptop_init_verbs },
16349 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16350 .dac_nids = alc861_dac_nids,
16351 .dig_out_nid = ALC861_DIGOUT_NID,
16352 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
16353 .channel_mode = alc883_3ST_2ch_modes,
16354 .need_dac_fix = 1,
16355 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16356 .adc_nids = alc861_adc_nids,
16357 .input_mux = &alc861_capture_source,
16358 },
16359};
Kailang Yangdf694da2005-12-05 19:42:22 +010016360
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016361/* Pin config fixes */
16362enum {
16363 PINFIX_FSC_AMILO_PI1505,
16364};
16365
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016366static const struct alc_fixup alc861_fixups[] = {
16367 [PINFIX_FSC_AMILO_PI1505] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010016368 .type = ALC_FIXUP_PINS,
16369 .v.pins = (const struct alc_pincfg[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020016370 { 0x0b, 0x0221101f }, /* HP */
16371 { 0x0f, 0x90170310 }, /* speaker */
16372 { }
16373 }
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016374 },
16375};
16376
16377static struct snd_pci_quirk alc861_fixup_tbl[] = {
16378 SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
16379 {}
16380};
Kailang Yangdf694da2005-12-05 19:42:22 +010016381
16382static int patch_alc861(struct hda_codec *codec)
16383{
16384 struct alc_spec *spec;
16385 int board_config;
16386 int err;
16387
Robert P. J. Daydc041e02006-12-19 14:44:15 +010016388 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010016389 if (spec == NULL)
16390 return -ENOMEM;
16391
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016392 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010016393
Takashi Iwaif5fcc132006-11-24 17:07:44 +010016394 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
16395 alc861_models,
16396 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016397
Takashi Iwaif5fcc132006-11-24 17:07:44 +010016398 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020016399 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
16400 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010016401 board_config = ALC861_AUTO;
16402 }
16403
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010016404 if (board_config == ALC861_AUTO) {
16405 alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
16406 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
16407 }
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016408
Kailang Yangdf694da2005-12-05 19:42:22 +010016409 if (board_config == ALC861_AUTO) {
16410 /* automatic parse from the BIOS config */
16411 err = alc861_parse_auto_config(codec);
16412 if (err < 0) {
16413 alc_free(codec);
16414 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016415 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016416 printk(KERN_INFO
16417 "hda_codec: Cannot set up configuration "
16418 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010016419 board_config = ALC861_3ST_DIG;
16420 }
16421 }
16422
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090016423 err = snd_hda_attach_beep_device(codec, 0x23);
16424 if (err < 0) {
16425 alc_free(codec);
16426 return err;
16427 }
16428
Kailang Yangdf694da2005-12-05 19:42:22 +010016429 if (board_config != ALC861_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020016430 setup_preset(codec, &alc861_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010016431
Kailang Yangdf694da2005-12-05 19:42:22 +010016432 spec->stream_analog_playback = &alc861_pcm_analog_playback;
16433 spec->stream_analog_capture = &alc861_pcm_analog_capture;
16434
Kailang Yangdf694da2005-12-05 19:42:22 +010016435 spec->stream_digital_playback = &alc861_pcm_digital_playback;
16436 spec->stream_digital_capture = &alc861_pcm_digital_capture;
16437
Takashi Iwaic7a8eb12010-01-14 12:39:02 +010016438 if (!spec->cap_mixer)
16439 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010016440 set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
16441
Takashi Iwai2134ea42008-01-10 16:53:55 +010016442 spec->vmaster_nid = 0x03;
16443
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010016444 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwai7fa90e82010-04-12 08:49:00 +020016445
Kailang Yangdf694da2005-12-05 19:42:22 +010016446 codec->patch_ops = alc_patch_ops;
Daniel T Chenc97259d2009-12-27 18:52:08 -050016447 if (board_config == ALC861_AUTO) {
Takashi Iwaiae6b8132006-03-03 16:47:17 +010016448 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020016449#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050016450 spec->power_hook = alc_power_eapd;
16451#endif
16452 }
16453#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaicb53c622007-08-10 17:21:45 +020016454 if (!spec->loopback.amplist)
16455 spec->loopback.amplist = alc861_loopbacks;
16456#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020016457
Kailang Yangdf694da2005-12-05 19:42:22 +010016458 return 0;
16459}
16460
16461/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016462 * ALC861-VD support
16463 *
16464 * Based on ALC882
16465 *
16466 * In addition, an independent DAC
16467 */
16468#define ALC861VD_DIGOUT_NID 0x06
16469
16470static hda_nid_t alc861vd_dac_nids[4] = {
16471 /* front, surr, clfe, side surr */
16472 0x02, 0x03, 0x04, 0x05
16473};
16474
16475/* dac_nids for ALC660vd are in a different order - according to
16476 * Realtek's driver.
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016477 * This should probably result in a different mixer for 6stack models
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016478 * of ALC660vd codecs, but for now there is only 3stack mixer
16479 * - and it is the same as in 861vd.
16480 * adc_nids in ALC660vd are (is) the same as in 861vd
16481 */
16482static hda_nid_t alc660vd_dac_nids[3] = {
16483 /* front, rear, clfe, rear_surr */
16484 0x02, 0x04, 0x03
16485};
16486
16487static hda_nid_t alc861vd_adc_nids[1] = {
16488 /* ADC0 */
16489 0x09,
16490};
16491
Takashi Iwaie1406342008-02-11 18:32:32 +010016492static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
16493
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016494/* input MUX */
16495/* FIXME: should be a matrix-type input source selection */
16496static struct hda_input_mux alc861vd_capture_source = {
16497 .num_items = 4,
16498 .items = {
16499 { "Mic", 0x0 },
16500 { "Front Mic", 0x1 },
16501 { "Line", 0x2 },
16502 { "CD", 0x4 },
16503 },
16504};
16505
Kailang Yang272a5272007-05-14 11:00:38 +020016506static struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010016507 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020016508 .items = {
David Henningsson8607f7c2010-12-20 14:43:54 +010016509 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +010016510 { "Internal Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020016511 },
16512};
16513
Kailang Yangd1a991a2007-08-15 16:21:59 +020016514static struct hda_input_mux alc861vd_hp_capture_source = {
16515 .num_items = 2,
16516 .items = {
16517 { "Front Mic", 0x0 },
16518 { "ATAPI Mic", 0x1 },
16519 },
16520};
16521
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016522/*
16523 * 2ch mode
16524 */
16525static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
16526 { 2, NULL }
16527};
16528
16529/*
16530 * 6ch mode
16531 */
16532static struct hda_verb alc861vd_6stack_ch6_init[] = {
16533 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
16534 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16535 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16536 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16537 { } /* end */
16538};
16539
16540/*
16541 * 8ch mode
16542 */
16543static struct hda_verb alc861vd_6stack_ch8_init[] = {
16544 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16545 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16546 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16547 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16548 { } /* end */
16549};
16550
16551static struct hda_channel_mode alc861vd_6stack_modes[2] = {
16552 { 6, alc861vd_6stack_ch6_init },
16553 { 8, alc861vd_6stack_ch8_init },
16554};
16555
16556static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
16557 {
16558 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
16559 .name = "Channel Mode",
16560 .info = alc_ch_mode_info,
16561 .get = alc_ch_mode_get,
16562 .put = alc_ch_mode_put,
16563 },
16564 { } /* end */
16565};
16566
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016567/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
16568 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
16569 */
16570static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
16571 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16572 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16573
16574 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16575 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
16576
16577 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
16578 HDA_OUTPUT),
16579 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
16580 HDA_OUTPUT),
16581 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
16582 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
16583
16584 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
16585 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
16586
16587 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16588
David Henningsson5f99f862011-01-04 15:24:24 +010016589 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016590 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16591 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16592
David Henningsson5f99f862011-01-04 15:24:24 +010016593 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016594 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16595 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16596
16597 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16598 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16599
16600 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16601 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16602
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016603 { } /* end */
16604};
16605
16606static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
16607 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16608 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16609
16610 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16611
David Henningsson5f99f862011-01-04 15:24:24 +010016612 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016613 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16614 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16615
David Henningsson5f99f862011-01-04 15:24:24 +010016616 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016617 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16618 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16619
16620 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16621 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16622
16623 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16624 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16625
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016626 { } /* end */
16627};
16628
Kailang Yangbdd148a2007-05-08 15:19:08 +020016629static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
16630 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16631 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
16632 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
16633
16634 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16635
David Henningsson5f99f862011-01-04 15:24:24 +010016636 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +020016637 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16638 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16639
David Henningsson5f99f862011-01-04 15:24:24 +010016640 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +020016641 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16642 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16643
16644 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16645 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16646
16647 { } /* end */
16648};
16649
Tobin Davisb419f342008-03-07 11:57:51 +010016650/* Pin assignment: Speaker=0x14, HP = 0x15,
David Henningsson8607f7c2010-12-20 14:43:54 +010016651 * Mic=0x18, Internal Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020016652 */
16653static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010016654 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16655 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020016656 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16657 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010016658 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
David Henningsson8607f7c2010-12-20 14:43:54 +010016659 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16660 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010016661 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +010016662 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16663 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020016664 { } /* end */
16665};
16666
Kailang Yangd1a991a2007-08-15 16:21:59 +020016667/* Pin assignment: Speaker=0x14, Line-out = 0x15,
16668 * Front Mic=0x18, ATAPI Mic = 0x19,
16669 */
16670static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
16671 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16672 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16673 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16674 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
16675 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16676 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16677 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16678 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020016679
Kailang Yangd1a991a2007-08-15 16:21:59 +020016680 { } /* end */
16681};
16682
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016683/*
16684 * generic initialization of ADC, input mixers and output mixers
16685 */
16686static struct hda_verb alc861vd_volume_init_verbs[] = {
16687 /*
16688 * Unmute ADC0 and set the default input to mic-in
16689 */
16690 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
16691 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16692
16693 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
16694 * the analog-loopback mixer widget
16695 */
16696 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020016697 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16698 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16699 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16700 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16701 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016702
16703 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020016704 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16705 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16706 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016707 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016708
16709 /*
16710 * Set up output mixers (0x02 - 0x05)
16711 */
16712 /* set vol=0 to output mixers */
16713 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16714 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16715 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16716 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16717
16718 /* set up input amps for analog loopback */
16719 /* Amp Indices: DAC = 0, mixer = 1 */
16720 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16721 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16722 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16723 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16724 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16725 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16726 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16727 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16728
16729 { }
16730};
16731
16732/*
16733 * 3-stack pin configuration:
16734 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
16735 */
16736static struct hda_verb alc861vd_3stack_init_verbs[] = {
16737 /*
16738 * Set pin mode and muting
16739 */
16740 /* set front pin widgets 0x14 for output */
16741 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16742 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16743 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16744
16745 /* Mic (rear) pin: input vref at 80% */
16746 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16747 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16748 /* Front Mic pin: input vref at 80% */
16749 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16750 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16751 /* Line In pin: input */
16752 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16753 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16754 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16755 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16756 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16757 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16758 /* CD pin widget for input */
16759 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16760
16761 { }
16762};
16763
16764/*
16765 * 6-stack pin configuration:
16766 */
16767static struct hda_verb alc861vd_6stack_init_verbs[] = {
16768 /*
16769 * Set pin mode and muting
16770 */
16771 /* set front pin widgets 0x14 for output */
16772 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16773 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16774 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16775
16776 /* Rear Pin: output 1 (0x0d) */
16777 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16778 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16779 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
16780 /* CLFE Pin: output 2 (0x0e) */
16781 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16782 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16783 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
16784 /* Side Pin: output 3 (0x0f) */
16785 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16786 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16787 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
16788
16789 /* Mic (rear) pin: input vref at 80% */
16790 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16791 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16792 /* Front Mic pin: input vref at 80% */
16793 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16794 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16795 /* Line In pin: input */
16796 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16797 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16798 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16799 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16800 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16801 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16802 /* CD pin widget for input */
16803 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16804
16805 { }
16806};
16807
Kailang Yangbdd148a2007-05-08 15:19:08 +020016808static struct hda_verb alc861vd_eapd_verbs[] = {
16809 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16810 { }
16811};
16812
Kailang Yangf9423e72008-05-27 12:32:25 +020016813static struct hda_verb alc660vd_eapd_verbs[] = {
16814 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16815 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
16816 { }
16817};
16818
Kailang Yangbdd148a2007-05-08 15:19:08 +020016819static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
16820 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16821 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16822 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
16823 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020016824 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020016825 {}
16826};
16827
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016828static void alc861vd_lenovo_setup(struct hda_codec *codec)
Kailang Yangbdd148a2007-05-08 15:19:08 +020016829{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016830 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016831 spec->autocfg.hp_pins[0] = 0x1b;
16832 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016833}
16834
16835static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
16836{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016837 alc_automute_amp(codec);
Anisse Astiereeb43382010-12-16 12:19:47 +010016838 alc88x_simple_mic_automute(codec);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016839}
16840
16841static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
16842 unsigned int res)
16843{
16844 switch (res >> 26) {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016845 case ALC880_MIC_EVENT:
Anisse Astiereeb43382010-12-16 12:19:47 +010016846 alc88x_simple_mic_automute(codec);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016847 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016848 default:
16849 alc_automute_amp_unsol_event(codec, res);
16850 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +020016851 }
16852}
16853
Kailang Yang272a5272007-05-14 11:00:38 +020016854static struct hda_verb alc861vd_dallas_verbs[] = {
16855 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16856 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16857 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16858 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16859
16860 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16861 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16862 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16863 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16864 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16865 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16866 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16867 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016868
Kailang Yang272a5272007-05-14 11:00:38 +020016869 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16870 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16871 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16872 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16873 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16874 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16875 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16876 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16877
16878 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16879 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16880 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16881 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16882 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16883 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16884 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16885 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16886
16887 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16888 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16889 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16890 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
16891
16892 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016893 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020016894 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16895
16896 { } /* end */
16897};
16898
16899/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016900static void alc861vd_dallas_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +020016901{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016902 struct alc_spec *spec = codec->spec;
Kailang Yang272a5272007-05-14 11:00:38 +020016903
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016904 spec->autocfg.hp_pins[0] = 0x15;
16905 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang272a5272007-05-14 11:00:38 +020016906}
16907
Takashi Iwaicb53c622007-08-10 17:21:45 +020016908#ifdef CONFIG_SND_HDA_POWER_SAVE
16909#define alc861vd_loopbacks alc880_loopbacks
16910#endif
16911
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016912/* pcm configuration: identical with ALC880 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016913#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
16914#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
16915#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
16916#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
16917
16918/*
16919 * configuration and preset
16920 */
Takashi Iwaiea734962011-01-17 11:29:34 +010016921static const char * const alc861vd_models[ALC861VD_MODEL_LAST] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016922 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016923 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Takashi Iwai13c94742008-11-05 08:06:08 +010016924 [ALC660VD_ASUS_V1S] = "asus-v1s",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016925 [ALC861VD_3ST] = "3stack",
16926 [ALC861VD_3ST_DIG] = "3stack-digout",
16927 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020016928 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020016929 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016930 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016931 [ALC861VD_AUTO] = "auto",
16932};
16933
16934static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016935 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
16936 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010016937 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016938 /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */
Takashi Iwai13c94742008-11-05 08:06:08 +010016939 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
Mike Crash6963f842007-06-25 12:12:51 +020016940 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016941 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016942 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020016943 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Takashi Iwaice577e82009-08-03 08:23:52 +020016944 SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai542d7c62007-08-16 18:57:30 +020016945 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010016946 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020016947 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016948 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020016949 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016950 {}
16951};
16952
16953static struct alc_config_preset alc861vd_presets[] = {
16954 [ALC660VD_3ST] = {
16955 .mixers = { alc861vd_3st_mixer },
16956 .init_verbs = { alc861vd_volume_init_verbs,
16957 alc861vd_3stack_init_verbs },
16958 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16959 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016960 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16961 .channel_mode = alc861vd_3stack_2ch_modes,
16962 .input_mux = &alc861vd_capture_source,
16963 },
Mike Crash6963f842007-06-25 12:12:51 +020016964 [ALC660VD_3ST_DIG] = {
16965 .mixers = { alc861vd_3st_mixer },
16966 .init_verbs = { alc861vd_volume_init_verbs,
16967 alc861vd_3stack_init_verbs },
16968 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16969 .dac_nids = alc660vd_dac_nids,
16970 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020016971 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16972 .channel_mode = alc861vd_3stack_2ch_modes,
16973 .input_mux = &alc861vd_capture_source,
16974 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016975 [ALC861VD_3ST] = {
16976 .mixers = { alc861vd_3st_mixer },
16977 .init_verbs = { alc861vd_volume_init_verbs,
16978 alc861vd_3stack_init_verbs },
16979 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16980 .dac_nids = alc861vd_dac_nids,
16981 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16982 .channel_mode = alc861vd_3stack_2ch_modes,
16983 .input_mux = &alc861vd_capture_source,
16984 },
16985 [ALC861VD_3ST_DIG] = {
16986 .mixers = { alc861vd_3st_mixer },
16987 .init_verbs = { alc861vd_volume_init_verbs,
16988 alc861vd_3stack_init_verbs },
16989 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16990 .dac_nids = alc861vd_dac_nids,
16991 .dig_out_nid = ALC861VD_DIGOUT_NID,
16992 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16993 .channel_mode = alc861vd_3stack_2ch_modes,
16994 .input_mux = &alc861vd_capture_source,
16995 },
16996 [ALC861VD_6ST_DIG] = {
16997 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
16998 .init_verbs = { alc861vd_volume_init_verbs,
16999 alc861vd_6stack_init_verbs },
17000 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
17001 .dac_nids = alc861vd_dac_nids,
17002 .dig_out_nid = ALC861VD_DIGOUT_NID,
17003 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
17004 .channel_mode = alc861vd_6stack_modes,
17005 .input_mux = &alc861vd_capture_source,
17006 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020017007 [ALC861VD_LENOVO] = {
17008 .mixers = { alc861vd_lenovo_mixer },
17009 .init_verbs = { alc861vd_volume_init_verbs,
17010 alc861vd_3stack_init_verbs,
17011 alc861vd_eapd_verbs,
17012 alc861vd_lenovo_unsol_verbs },
17013 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
17014 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020017015 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
17016 .channel_mode = alc861vd_3stack_2ch_modes,
17017 .input_mux = &alc861vd_capture_source,
17018 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017019 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020017020 .init_hook = alc861vd_lenovo_init_hook,
Kailang Yangbdd148a2007-05-08 15:19:08 +020017021 },
Kailang Yang272a5272007-05-14 11:00:38 +020017022 [ALC861VD_DALLAS] = {
17023 .mixers = { alc861vd_dallas_mixer },
17024 .init_verbs = { alc861vd_dallas_verbs },
17025 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
17026 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020017027 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
17028 .channel_mode = alc861vd_3stack_2ch_modes,
17029 .input_mux = &alc861vd_dallas_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020017030 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017031 .setup = alc861vd_dallas_setup,
17032 .init_hook = alc_automute_amp,
Kailang Yangd1a991a2007-08-15 16:21:59 +020017033 },
17034 [ALC861VD_HP] = {
17035 .mixers = { alc861vd_hp_mixer },
17036 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
17037 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
17038 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020017039 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020017040 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
17041 .channel_mode = alc861vd_3stack_2ch_modes,
17042 .input_mux = &alc861vd_hp_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020017043 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017044 .setup = alc861vd_dallas_setup,
17045 .init_hook = alc_automute_amp,
Kailang Yangea1fb292008-08-26 12:58:38 +020017046 },
Takashi Iwai13c94742008-11-05 08:06:08 +010017047 [ALC660VD_ASUS_V1S] = {
17048 .mixers = { alc861vd_lenovo_mixer },
17049 .init_verbs = { alc861vd_volume_init_verbs,
17050 alc861vd_3stack_init_verbs,
17051 alc861vd_eapd_verbs,
17052 alc861vd_lenovo_unsol_verbs },
17053 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
17054 .dac_nids = alc660vd_dac_nids,
17055 .dig_out_nid = ALC861VD_DIGOUT_NID,
17056 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
17057 .channel_mode = alc861vd_3stack_2ch_modes,
17058 .input_mux = &alc861vd_capture_source,
17059 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017060 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020017061 .init_hook = alc861vd_lenovo_init_hook,
Takashi Iwai13c94742008-11-05 08:06:08 +010017062 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017063};
17064
17065/*
17066 * BIOS auto configuration
17067 */
Takashi Iwai05f5f472009-08-25 13:10:18 +020017068static int alc861vd_auto_create_input_ctls(struct hda_codec *codec,
17069 const struct auto_pin_cfg *cfg)
17070{
Herton Ronaldo Krzesinski71675942010-11-25 00:08:01 -020017071 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x22, 0);
Takashi Iwai05f5f472009-08-25 13:10:18 +020017072}
17073
17074
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017075static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
17076 hda_nid_t nid, int pin_type, int dac_idx)
17077{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017078 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017079}
17080
17081static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
17082{
17083 struct alc_spec *spec = codec->spec;
17084 int i;
17085
17086 for (i = 0; i <= HDA_SIDE; i++) {
17087 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020017088 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017089 if (nid)
17090 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020017091 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017092 }
17093}
17094
17095
17096static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
17097{
17098 struct alc_spec *spec = codec->spec;
17099 hda_nid_t pin;
17100
17101 pin = spec->autocfg.hp_pins[0];
Sasha Alexandrdef319f2009-06-16 16:00:15 -040017102 if (pin) /* connect to front and use dac 0 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017103 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017104 pin = spec->autocfg.speaker_pins[0];
17105 if (pin)
17106 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017107}
17108
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017109#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
17110
17111static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
17112{
17113 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020017114 struct auto_pin_cfg *cfg = &spec->autocfg;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017115 int i;
17116
Takashi Iwai66ceeb62010-08-30 13:05:52 +020017117 for (i = 0; i < cfg->num_inputs; i++) {
17118 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +020017119 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai30ea0982010-09-16 18:47:56 +020017120 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwaie82c0252009-03-23 15:17:38 +010017121 if (nid != ALC861VD_PIN_CD_NID &&
17122 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017123 snd_hda_codec_write(codec, nid, 0,
17124 AC_VERB_SET_AMP_GAIN_MUTE,
17125 AMP_OUT_MUTE);
17126 }
17127 }
17128}
17129
Takashi Iwaif511b012008-08-15 16:46:42 +020017130#define alc861vd_auto_init_input_src alc882_auto_init_input_src
17131
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017132#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
17133#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
17134
17135/* add playback controls from the parsed DAC table */
Takashi Iwai569ed342011-01-19 10:14:46 +010017136/* Based on ALC880 version. But ALC861VD has separate,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017137 * different NIDs for mute/unmute switch and volume control */
17138static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
17139 const struct auto_pin_cfg *cfg)
17140{
Takashi Iwaiea734962011-01-17 11:29:34 +010017141 static const char * const chname[4] = {
17142 "Front", "Surround", "CLFE", "Side"
17143 };
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010017144 const char *pfx = alc_get_line_out_pfx(cfg, true);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017145 hda_nid_t nid_v, nid_s;
17146 int i, err;
17147
17148 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017149 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017150 continue;
17151 nid_v = alc861vd_idx_to_mixer_vol(
17152 alc880_dac_to_idx(
17153 spec->multiout.dac_nids[i]));
17154 nid_s = alc861vd_idx_to_mixer_switch(
17155 alc880_dac_to_idx(
17156 spec->multiout.dac_nids[i]));
17157
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010017158 if (!pfx && i == 2) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017159 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017160 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
17161 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017162 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
17163 HDA_OUTPUT));
17164 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017165 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017166 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
17167 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017168 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
17169 HDA_OUTPUT));
17170 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017171 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017172 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
17173 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017174 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
17175 HDA_INPUT));
17176 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017177 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017178 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
17179 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017180 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
17181 HDA_INPUT));
17182 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017183 return err;
17184 } else {
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010017185 const char *name = pfx;
17186 if (!name)
17187 name = chname[i];
17188 err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
17189 name, i,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017190 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
17191 HDA_OUTPUT));
17192 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017193 return err;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010017194 err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
17195 name, i,
Kailang Yangbdd148a2007-05-08 15:19:08 +020017196 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017197 HDA_INPUT));
17198 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017199 return err;
17200 }
17201 }
17202 return 0;
17203}
17204
17205/* add playback controls for speaker and HP outputs */
17206/* Based on ALC880 version. But ALC861VD has separate,
17207 * different NIDs for mute/unmute switch and volume control */
17208static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
17209 hda_nid_t pin, const char *pfx)
17210{
17211 hda_nid_t nid_v, nid_s;
17212 int err;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017213
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017214 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017215 return 0;
17216
17217 if (alc880_is_fixed_pin(pin)) {
17218 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
17219 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017220 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017221 spec->multiout.hp_nid = nid_v;
17222 else
17223 spec->multiout.extra_out_nid[0] = nid_v;
17224 /* control HP volume/switch on the output mixer amp */
17225 nid_v = alc861vd_idx_to_mixer_vol(
17226 alc880_fixed_pin_idx(pin));
17227 nid_s = alc861vd_idx_to_mixer_switch(
17228 alc880_fixed_pin_idx(pin));
17229
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017230 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017231 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
17232 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017233 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017234 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017235 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
17236 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017237 return err;
17238 } else if (alc880_is_multi_pin(pin)) {
17239 /* set manual connection */
17240 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017241 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017242 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
17243 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017244 return err;
17245 }
17246 return 0;
17247}
17248
17249/* parse the BIOS configuration and set up the alc_spec
17250 * return 1 if successful, 0 if the proper config is not found,
17251 * or a negative error code
17252 * Based on ALC880 version - had to change it to override
17253 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
17254static int alc861vd_parse_auto_config(struct hda_codec *codec)
17255{
17256 struct alc_spec *spec = codec->spec;
17257 int err;
17258 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
17259
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017260 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
17261 alc861vd_ignore);
17262 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017263 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017264 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017265 return 0; /* can't find valid BIOS pin config */
17266
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017267 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
17268 if (err < 0)
17269 return err;
17270 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
17271 if (err < 0)
17272 return err;
17273 err = alc861vd_auto_create_extra_out(spec,
17274 spec->autocfg.speaker_pins[0],
17275 "Speaker");
17276 if (err < 0)
17277 return err;
17278 err = alc861vd_auto_create_extra_out(spec,
17279 spec->autocfg.hp_pins[0],
17280 "Headphone");
17281 if (err < 0)
17282 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020017283 err = alc861vd_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017284 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017285 return err;
17286
17287 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
17288
Takashi Iwai757899a2010-07-30 10:48:14 +020017289 alc_auto_parse_digital(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017290
Takashi Iwai603c4012008-07-30 15:01:44 +020017291 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010017292 add_mixer(spec, spec->kctls.list);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017293
Takashi Iwaid88897e2008-10-31 15:01:37 +010017294 add_verb(spec, alc861vd_volume_init_verbs);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017295
17296 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020017297 spec->input_mux = &spec->private_imux[0];
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017298
Takashi Iwai776e1842007-08-29 15:07:11 +020017299 err = alc_auto_add_mic_boost(codec);
17300 if (err < 0)
17301 return err;
17302
Kailang Yang6227cdc2010-02-25 08:36:52 +010017303 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020017304
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017305 return 1;
17306}
17307
17308/* additional initialization for auto-configuration model */
17309static void alc861vd_auto_init(struct hda_codec *codec)
17310{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017311 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017312 alc861vd_auto_init_multi_out(codec);
17313 alc861vd_auto_init_hp_out(codec);
17314 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020017315 alc861vd_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020017316 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017317 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020017318 alc_inithook(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017319}
17320
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017321enum {
17322 ALC660VD_FIX_ASUS_GPIO1
17323};
17324
17325/* reset GPIO1 */
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017326static const struct alc_fixup alc861vd_fixups[] = {
17327 [ALC660VD_FIX_ASUS_GPIO1] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010017328 .type = ALC_FIXUP_VERBS,
17329 .v.verbs = (const struct hda_verb[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020017330 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
17331 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
17332 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
17333 { }
17334 }
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017335 },
17336};
17337
17338static struct snd_pci_quirk alc861vd_fixup_tbl[] = {
17339 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
17340 {}
17341};
17342
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017343static int patch_alc861vd(struct hda_codec *codec)
17344{
17345 struct alc_spec *spec;
17346 int err, board_config;
17347
17348 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
17349 if (spec == NULL)
17350 return -ENOMEM;
17351
17352 codec->spec = spec;
17353
17354 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
17355 alc861vd_models,
17356 alc861vd_cfg_tbl);
17357
17358 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020017359 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
17360 codec->chip_name);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017361 board_config = ALC861VD_AUTO;
17362 }
17363
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010017364 if (board_config == ALC861VD_AUTO) {
17365 alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
17366 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
17367 }
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017368
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017369 if (board_config == ALC861VD_AUTO) {
17370 /* automatic parse from the BIOS config */
17371 err = alc861vd_parse_auto_config(codec);
17372 if (err < 0) {
17373 alc_free(codec);
17374 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017375 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017376 printk(KERN_INFO
17377 "hda_codec: Cannot set up configuration "
17378 "from BIOS. Using base mode...\n");
17379 board_config = ALC861VD_3ST;
17380 }
17381 }
17382
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090017383 err = snd_hda_attach_beep_device(codec, 0x23);
17384 if (err < 0) {
17385 alc_free(codec);
17386 return err;
17387 }
17388
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017389 if (board_config != ALC861VD_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020017390 setup_preset(codec, &alc861vd_presets[board_config]);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017391
Kailang Yang2f893282008-05-27 12:14:47 +020017392 if (codec->vendor_id == 0x10ec0660) {
Kailang Yangf9423e72008-05-27 12:32:25 +020017393 /* always turn on EAPD */
Takashi Iwaid88897e2008-10-31 15:01:37 +010017394 add_verb(spec, alc660vd_eapd_verbs);
Kailang Yang2f893282008-05-27 12:14:47 +020017395 }
17396
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017397 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
17398 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
17399
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017400 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
17401 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
17402
Takashi Iwaidd704692009-08-11 08:45:11 +020017403 if (!spec->adc_nids) {
17404 spec->adc_nids = alc861vd_adc_nids;
17405 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
17406 }
17407 if (!spec->capsrc_nids)
17408 spec->capsrc_nids = alc861vd_capsrc_nids;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017409
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017410 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010017411 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017412
Takashi Iwai2134ea42008-01-10 16:53:55 +010017413 spec->vmaster_nid = 0x02;
17414
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010017415 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwai7fa90e82010-04-12 08:49:00 +020017416
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017417 codec->patch_ops = alc_patch_ops;
17418
17419 if (board_config == ALC861VD_AUTO)
17420 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020017421#ifdef CONFIG_SND_HDA_POWER_SAVE
17422 if (!spec->loopback.amplist)
17423 spec->loopback.amplist = alc861vd_loopbacks;
17424#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017425
17426 return 0;
17427}
17428
17429/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017430 * ALC662 support
17431 *
17432 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
17433 * configuration. Each pin widget can choose any input DACs and a mixer.
17434 * Each ADC is connected from a mixer of all inputs. This makes possible
17435 * 6-channel independent captures.
17436 *
17437 * In addition, an independent DAC for the multi-playback (not used in this
17438 * driver yet).
17439 */
17440#define ALC662_DIGOUT_NID 0x06
17441#define ALC662_DIGIN_NID 0x0a
17442
17443static hda_nid_t alc662_dac_nids[4] = {
17444 /* front, rear, clfe, rear_surr */
17445 0x02, 0x03, 0x04
17446};
17447
Kailang Yang622e84c2009-04-21 07:39:04 +020017448static hda_nid_t alc272_dac_nids[2] = {
17449 0x02, 0x03
17450};
17451
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017452static hda_nid_t alc662_adc_nids[2] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017453 /* ADC1-2 */
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017454 0x09, 0x08
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017455};
Takashi Iwaie1406342008-02-11 18:32:32 +010017456
Kailang Yang622e84c2009-04-21 07:39:04 +020017457static hda_nid_t alc272_adc_nids[1] = {
17458 /* ADC1-2 */
17459 0x08,
17460};
17461
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017462static hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 };
Kailang Yang622e84c2009-04-21 07:39:04 +020017463static hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
17464
Takashi Iwaie1406342008-02-11 18:32:32 +010017465
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017466/* input MUX */
17467/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017468static struct hda_input_mux alc662_capture_source = {
17469 .num_items = 4,
17470 .items = {
17471 { "Mic", 0x0 },
17472 { "Front Mic", 0x1 },
17473 { "Line", 0x2 },
17474 { "CD", 0x4 },
17475 },
17476};
17477
17478static struct hda_input_mux alc662_lenovo_101e_capture_source = {
17479 .num_items = 2,
17480 .items = {
17481 { "Mic", 0x1 },
17482 { "Line", 0x2 },
17483 },
17484};
Kailang Yang291702f2007-10-16 14:28:03 +020017485
Kailang Yang6dda9f42008-05-27 12:05:31 +020017486static struct hda_input_mux alc663_capture_source = {
17487 .num_items = 3,
17488 .items = {
17489 { "Mic", 0x0 },
17490 { "Front Mic", 0x1 },
17491 { "Line", 0x2 },
17492 },
17493};
17494
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017495#if 0 /* set to 1 for testing other input sources below */
Chris Pockelé9541ba12009-05-12 08:08:53 +020017496static struct hda_input_mux alc272_nc10_capture_source = {
17497 .num_items = 16,
17498 .items = {
17499 { "Autoselect Mic", 0x0 },
17500 { "Internal Mic", 0x1 },
17501 { "In-0x02", 0x2 },
17502 { "In-0x03", 0x3 },
17503 { "In-0x04", 0x4 },
17504 { "In-0x05", 0x5 },
17505 { "In-0x06", 0x6 },
17506 { "In-0x07", 0x7 },
17507 { "In-0x08", 0x8 },
17508 { "In-0x09", 0x9 },
17509 { "In-0x0a", 0x0a },
17510 { "In-0x0b", 0x0b },
17511 { "In-0x0c", 0x0c },
17512 { "In-0x0d", 0x0d },
17513 { "In-0x0e", 0x0e },
17514 { "In-0x0f", 0x0f },
17515 },
17516};
17517#endif
17518
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017519/*
17520 * 2ch mode
17521 */
17522static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
17523 { 2, NULL }
17524};
17525
17526/*
17527 * 2ch mode
17528 */
17529static struct hda_verb alc662_3ST_ch2_init[] = {
17530 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
17531 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
17532 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
17533 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
17534 { } /* end */
17535};
17536
17537/*
17538 * 6ch mode
17539 */
17540static struct hda_verb alc662_3ST_ch6_init[] = {
17541 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17542 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
17543 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
17544 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17545 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
17546 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
17547 { } /* end */
17548};
17549
17550static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
17551 { 2, alc662_3ST_ch2_init },
17552 { 6, alc662_3ST_ch6_init },
17553};
17554
17555/*
17556 * 2ch mode
17557 */
17558static struct hda_verb alc662_sixstack_ch6_init[] = {
17559 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
17560 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
17561 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17562 { } /* end */
17563};
17564
17565/*
17566 * 6ch mode
17567 */
17568static struct hda_verb alc662_sixstack_ch8_init[] = {
17569 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17570 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17571 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17572 { } /* end */
17573};
17574
17575static struct hda_channel_mode alc662_5stack_modes[2] = {
17576 { 2, alc662_sixstack_ch6_init },
17577 { 6, alc662_sixstack_ch8_init },
17578};
17579
17580/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
17581 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
17582 */
17583
17584static struct snd_kcontrol_new alc662_base_mixer[] = {
17585 /* output mixer control */
17586 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017587 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017588 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017589 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017590 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17591 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017592 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
17593 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017594 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17595
17596 /*Input mixer control */
17597 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
17598 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
17599 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
17600 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
17601 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
17602 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
17603 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
17604 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017605 { } /* end */
17606};
17607
17608static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
17609 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017610 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017611 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17612 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
17613 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
17614 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17615 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17616 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17617 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17618 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17619 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017620 { } /* end */
17621};
17622
17623static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
17624 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017625 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017626 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017627 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017628 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17629 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017630 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
17631 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017632 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17633 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
17634 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
17635 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17636 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17637 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17638 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17639 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17640 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017641 { } /* end */
17642};
17643
17644static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
17645 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17646 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010017647 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17648 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017649 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17650 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17651 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17652 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17653 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017654 { } /* end */
17655};
17656
Kailang Yang291702f2007-10-16 14:28:03 +020017657static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020017658 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17659 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang291702f2007-10-16 14:28:03 +020017660
David Henningsson5f99f862011-01-04 15:24:24 +010017661 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017662 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17663 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020017664
David Henningsson5f99f862011-01-04 15:24:24 +010017665 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017666 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17667 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020017668 { } /* end */
17669};
17670
Kailang Yang8c427222008-01-10 13:03:59 +010017671static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020017672 ALC262_HIPPO_MASTER_SWITCH,
17673 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017674 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017675 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17676 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017677 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
17678 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17679 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17680 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17681 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17682 { } /* end */
17683};
17684
Kailang Yangf1d4e282008-08-26 14:03:29 +020017685static struct hda_bind_ctls alc663_asus_bind_master_vol = {
17686 .ops = &snd_hda_bind_vol,
17687 .values = {
17688 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17689 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
17690 0
17691 },
17692};
17693
17694static struct hda_bind_ctls alc663_asus_one_bind_switch = {
17695 .ops = &snd_hda_bind_sw,
17696 .values = {
17697 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17698 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17699 0
17700 },
17701};
17702
Kailang Yang6dda9f42008-05-27 12:05:31 +020017703static struct snd_kcontrol_new alc663_m51va_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017704 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17705 HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
17706 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17707 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17708 { } /* end */
17709};
17710
17711static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
17712 .ops = &snd_hda_bind_sw,
17713 .values = {
17714 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17715 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17716 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17717 0
17718 },
17719};
17720
17721static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
17722 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17723 HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
17724 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17725 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17726 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17727 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17728
17729 { } /* end */
17730};
17731
17732static struct hda_bind_ctls alc663_asus_four_bind_switch = {
17733 .ops = &snd_hda_bind_sw,
17734 .values = {
17735 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17736 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17737 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17738 0
17739 },
17740};
17741
17742static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
17743 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17744 HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
17745 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17746 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17747 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17748 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17749 { } /* end */
17750};
17751
17752static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017753 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17754 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017755 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17756 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17757 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17758 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17759 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17760 { } /* end */
17761};
17762
17763static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
17764 .ops = &snd_hda_bind_vol,
17765 .values = {
17766 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17767 HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
17768 0
17769 },
17770};
17771
17772static struct hda_bind_ctls alc663_asus_two_bind_switch = {
17773 .ops = &snd_hda_bind_sw,
17774 .values = {
17775 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17776 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
17777 0
17778 },
17779};
17780
17781static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
17782 HDA_BIND_VOL("Master Playback Volume",
17783 &alc663_asus_two_bind_master_vol),
17784 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17785 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017786 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17787 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17788 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017789 { } /* end */
17790};
17791
17792static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
17793 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17794 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17795 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17796 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17797 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17798 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017799 { } /* end */
17800};
17801
17802static struct snd_kcontrol_new alc663_g71v_mixer[] = {
17803 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17804 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17805 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17806 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17807 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17808
17809 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17810 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017811 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17812 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017813 { } /* end */
17814};
17815
17816static struct snd_kcontrol_new alc663_g50v_mixer[] = {
17817 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17818 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17819 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17820
17821 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17822 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017823 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17824 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017825 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17826 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17827 { } /* end */
17828};
17829
Kailang Yangebb83ee2009-12-17 12:23:00 +010017830static struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = {
17831 .ops = &snd_hda_bind_sw,
17832 .values = {
17833 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17834 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17835 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17836 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17837 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17838 0
17839 },
17840};
17841
17842static struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = {
17843 .ops = &snd_hda_bind_sw,
17844 .values = {
17845 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17846 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17847 0
17848 },
17849};
17850
17851static struct snd_kcontrol_new alc663_mode7_mixer[] = {
17852 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17853 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17854 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17855 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17856 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17857 HDA_CODEC_VOLUME("IntMic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17858 HDA_CODEC_MUTE("IntMic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17859 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17860 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17861 { } /* end */
17862};
17863
17864static struct snd_kcontrol_new alc663_mode8_mixer[] = {
17865 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17866 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17867 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17868 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17869 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17870 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17871 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17872 { } /* end */
17873};
17874
17875
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017876static struct snd_kcontrol_new alc662_chmode_mixer[] = {
17877 {
17878 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
17879 .name = "Channel Mode",
17880 .info = alc_ch_mode_info,
17881 .get = alc_ch_mode_get,
17882 .put = alc_ch_mode_put,
17883 },
17884 { } /* end */
17885};
17886
17887static struct hda_verb alc662_init_verbs[] = {
17888 /* ADC: mute amp left and right */
17889 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17890 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017891
Kailang Yangb60dd392007-09-20 12:50:29 +020017892 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17893 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17894 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17895 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17896 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17897 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017898
17899 /* Front Pin: output 0 (0x0c) */
17900 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17901 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17902
17903 /* Rear Pin: output 1 (0x0d) */
17904 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17905 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17906
17907 /* CLFE Pin: output 2 (0x0e) */
17908 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17909 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17910
17911 /* Mic (rear) pin: input vref at 80% */
17912 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17913 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17914 /* Front Mic pin: input vref at 80% */
17915 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17916 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17917 /* Line In pin: input */
17918 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17919 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17920 /* Line-2 In: Headphone output (output 0 - 0x0c) */
17921 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17922 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17923 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
17924 /* CD pin widget for input */
17925 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17926
17927 /* FIXME: use matrix-type input source selection */
17928 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
17929 /* Input mixer */
17930 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang291702f2007-10-16 14:28:03 +020017931 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017932
17933 /* always trun on EAPD */
17934 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
17935 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
17936
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017937 { }
17938};
17939
Kailang Yangcec27c82010-02-04 14:18:18 +010017940static struct hda_verb alc663_init_verbs[] = {
17941 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17942 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17943 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17944 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17945 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17946 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17947 { }
17948};
17949
17950static struct hda_verb alc272_init_verbs[] = {
17951 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17952 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17953 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17954 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17955 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17956 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17957 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17958 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17959 { }
17960};
17961
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017962static struct hda_verb alc662_sue_init_verbs[] = {
17963 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
17964 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020017965 {}
17966};
17967
17968static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
17969 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17970 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17971 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017972};
17973
Kailang Yang8c427222008-01-10 13:03:59 +010017974/* Set Unsolicited Event*/
17975static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
17976 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17977 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17978 {}
17979};
17980
Kailang Yang6dda9f42008-05-27 12:05:31 +020017981static struct hda_verb alc663_m51va_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017982 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17983 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017984 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17985 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf1d4e282008-08-26 14:03:29 +020017986 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17987 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17988 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017989 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17990 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17991 {}
17992};
17993
Kailang Yangf1d4e282008-08-26 14:03:29 +020017994static struct hda_verb alc663_21jd_amic_init_verbs[] = {
17995 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17996 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17997 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17998 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17999 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
18000 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18001 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18002 {}
18003};
18004
18005static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
18006 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18007 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18008 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18009 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
18010 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18011 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
18012 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18013 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18014 {}
18015};
18016
18017static struct hda_verb alc663_15jd_amic_init_verbs[] = {
18018 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18019 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18020 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18021 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18022 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
18023 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18024 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18025 {}
18026};
18027
18028static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
18029 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18030 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18031 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18032 {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
18033 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18034 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18035 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
18036 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18037 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
18038 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18039 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18040 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18041 {}
18042};
18043
18044static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
18045 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18046 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18047 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18048 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18049 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18050 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18051 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18052 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18053 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
18054 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18055 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18056 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18057 {}
18058};
18059
Kailang Yang6dda9f42008-05-27 12:05:31 +020018060static struct hda_verb alc663_g71v_init_verbs[] = {
18061 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18062 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
18063 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
18064
18065 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18066 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18067 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
18068
18069 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
18070 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
18071 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
18072 {}
18073};
18074
18075static struct hda_verb alc663_g50v_init_verbs[] = {
18076 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18077 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18078 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
18079
18080 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18081 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18082 {}
18083};
18084
Kailang Yangf1d4e282008-08-26 14:03:29 +020018085static struct hda_verb alc662_ecs_init_verbs[] = {
18086 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
18087 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18088 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18089 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18090 {}
18091};
18092
Kailang Yang622e84c2009-04-21 07:39:04 +020018093static struct hda_verb alc272_dell_zm1_init_verbs[] = {
18094 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18095 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18096 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18097 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18098 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18099 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18100 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18101 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18102 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
18103 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18104 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18105 {}
18106};
18107
18108static struct hda_verb alc272_dell_init_verbs[] = {
18109 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18110 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18111 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18112 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18113 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18114 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18115 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18116 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18117 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
18118 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18119 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18120 {}
18121};
18122
Kailang Yangebb83ee2009-12-17 12:23:00 +010018123static struct hda_verb alc663_mode7_init_verbs[] = {
18124 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18125 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18126 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
18127 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18128 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18129 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18130 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
18131 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18132 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18133 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18134 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18135 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
18136 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18137 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18138 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18139 {}
18140};
18141
18142static struct hda_verb alc663_mode8_init_verbs[] = {
18143 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18144 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18145 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18146 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
18147 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18148 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
18149 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18150 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18151 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18152 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18153 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18154 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18155 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
18156 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18157 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18158 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18159 {}
18160};
18161
Kailang Yangf1d4e282008-08-26 14:03:29 +020018162static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
18163 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
18164 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
18165 { } /* end */
18166};
18167
Kailang Yang622e84c2009-04-21 07:39:04 +020018168static struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
18169 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
18170 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
18171 { } /* end */
18172};
18173
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018174static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
18175{
18176 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018177 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018178
Wu Fengguang864f92b2009-11-18 12:38:02 +080018179 present = snd_hda_jack_detect(codec, 0x14);
Takashi Iwai47fd8302007-08-10 17:11:07 +020018180 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080018181
Takashi Iwai47fd8302007-08-10 17:11:07 +020018182 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
18183 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018184}
18185
18186static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
18187{
18188 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018189 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018190
Wu Fengguang864f92b2009-11-18 12:38:02 +080018191 present = snd_hda_jack_detect(codec, 0x1b);
Takashi Iwai47fd8302007-08-10 17:11:07 +020018192 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080018193
Takashi Iwai47fd8302007-08-10 17:11:07 +020018194 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
18195 HDA_AMP_MUTE, bits);
18196 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
18197 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018198}
18199
18200static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
18201 unsigned int res)
18202{
18203 if ((res >> 26) == ALC880_HP_EVENT)
18204 alc662_lenovo_101e_all_automute(codec);
18205 if ((res >> 26) == ALC880_FRONT_EVENT)
18206 alc662_lenovo_101e_ispeaker_automute(codec);
18207}
18208
Kailang Yang291702f2007-10-16 14:28:03 +020018209/* unsolicited event for HP jack sensing */
18210static void alc662_eeepc_unsol_event(struct hda_codec *codec,
18211 unsigned int res)
18212{
Kailang Yang291702f2007-10-16 14:28:03 +020018213 if ((res >> 26) == ALC880_MIC_EVENT)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018214 alc_mic_automute(codec);
Takashi Iwai42171c12009-05-08 14:11:43 +020018215 else
18216 alc262_hippo_unsol_event(codec, res);
Kailang Yang291702f2007-10-16 14:28:03 +020018217}
18218
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018219static void alc662_eeepc_setup(struct hda_codec *codec)
Kailang Yang291702f2007-10-16 14:28:03 +020018220{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018221 struct alc_spec *spec = codec->spec;
18222
18223 alc262_hippo1_setup(codec);
18224 spec->ext_mic.pin = 0x18;
18225 spec->ext_mic.mux_idx = 0;
18226 spec->int_mic.pin = 0x19;
18227 spec->int_mic.mux_idx = 1;
18228 spec->auto_mic = 1;
Kailang Yang291702f2007-10-16 14:28:03 +020018229}
18230
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018231static void alc662_eeepc_inithook(struct hda_codec *codec)
18232{
18233 alc262_hippo_automute(codec);
18234 alc_mic_automute(codec);
18235}
18236
18237static void alc662_eeepc_ep20_setup(struct hda_codec *codec)
Kailang Yang8c427222008-01-10 13:03:59 +010018238{
Takashi Iwai42171c12009-05-08 14:11:43 +020018239 struct alc_spec *spec = codec->spec;
18240
18241 spec->autocfg.hp_pins[0] = 0x14;
18242 spec->autocfg.speaker_pins[0] = 0x1b;
Kailang Yang8c427222008-01-10 13:03:59 +010018243}
18244
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018245#define alc662_eeepc_ep20_inithook alc262_hippo_master_update
18246
Kailang Yang6dda9f42008-05-27 12:05:31 +020018247static void alc663_m51va_speaker_automute(struct hda_codec *codec)
18248{
18249 unsigned int present;
18250 unsigned char bits;
18251
Wu Fengguang864f92b2009-11-18 12:38:02 +080018252 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018253 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yangf1d4e282008-08-26 14:03:29 +020018254 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018255 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018256 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018257 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018258}
18259
18260static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
18261{
18262 unsigned int present;
18263 unsigned char bits;
18264
Wu Fengguang864f92b2009-11-18 12:38:02 +080018265 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018266 bits = present ? HDA_AMP_MUTE : 0;
18267 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018268 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018269 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018270 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018271 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018272 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018273 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018274 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018275}
18276
18277static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
18278{
18279 unsigned int present;
18280 unsigned char bits;
18281
Wu Fengguang864f92b2009-11-18 12:38:02 +080018282 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018283 bits = present ? HDA_AMP_MUTE : 0;
18284 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018285 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018286 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018287 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018288 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018289 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018290 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018291 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018292}
18293
18294static void alc662_f5z_speaker_automute(struct hda_codec *codec)
18295{
18296 unsigned int present;
18297 unsigned char bits;
18298
Wu Fengguang864f92b2009-11-18 12:38:02 +080018299 present = snd_hda_jack_detect(codec, 0x1b);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018300 bits = present ? 0 : PIN_OUT;
18301 snd_hda_codec_write(codec, 0x14, 0,
18302 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
18303}
18304
18305static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
18306{
18307 unsigned int present1, present2;
18308
Wu Fengguang864f92b2009-11-18 12:38:02 +080018309 present1 = snd_hda_jack_detect(codec, 0x21);
18310 present2 = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018311
18312 if (present1 || present2) {
18313 snd_hda_codec_write_cache(codec, 0x14, 0,
18314 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
18315 } else {
18316 snd_hda_codec_write_cache(codec, 0x14, 0,
18317 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
18318 }
18319}
18320
18321static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
18322{
18323 unsigned int present1, present2;
18324
Wu Fengguang864f92b2009-11-18 12:38:02 +080018325 present1 = snd_hda_jack_detect(codec, 0x1b);
18326 present2 = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018327
18328 if (present1 || present2) {
18329 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018330 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018331 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018332 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018333 } else {
18334 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018335 HDA_AMP_MUTE, 0);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018336 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018337 HDA_AMP_MUTE, 0);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018338 }
Kailang Yang6dda9f42008-05-27 12:05:31 +020018339}
18340
Kailang Yangebb83ee2009-12-17 12:23:00 +010018341static void alc663_two_hp_m7_speaker_automute(struct hda_codec *codec)
18342{
18343 unsigned int present1, present2;
18344
18345 present1 = snd_hda_codec_read(codec, 0x1b, 0,
18346 AC_VERB_GET_PIN_SENSE, 0)
18347 & AC_PINSENSE_PRESENCE;
18348 present2 = snd_hda_codec_read(codec, 0x21, 0,
18349 AC_VERB_GET_PIN_SENSE, 0)
18350 & AC_PINSENSE_PRESENCE;
18351
18352 if (present1 || present2) {
18353 snd_hda_codec_write_cache(codec, 0x14, 0,
18354 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
18355 snd_hda_codec_write_cache(codec, 0x17, 0,
18356 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
18357 } else {
18358 snd_hda_codec_write_cache(codec, 0x14, 0,
18359 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
18360 snd_hda_codec_write_cache(codec, 0x17, 0,
18361 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
18362 }
18363}
18364
18365static void alc663_two_hp_m8_speaker_automute(struct hda_codec *codec)
18366{
18367 unsigned int present1, present2;
18368
18369 present1 = snd_hda_codec_read(codec, 0x21, 0,
18370 AC_VERB_GET_PIN_SENSE, 0)
18371 & AC_PINSENSE_PRESENCE;
18372 present2 = snd_hda_codec_read(codec, 0x15, 0,
18373 AC_VERB_GET_PIN_SENSE, 0)
18374 & AC_PINSENSE_PRESENCE;
18375
18376 if (present1 || present2) {
18377 snd_hda_codec_write_cache(codec, 0x14, 0,
18378 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
18379 snd_hda_codec_write_cache(codec, 0x17, 0,
18380 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
18381 } else {
18382 snd_hda_codec_write_cache(codec, 0x14, 0,
18383 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
18384 snd_hda_codec_write_cache(codec, 0x17, 0,
18385 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
18386 }
18387}
18388
Kailang Yang6dda9f42008-05-27 12:05:31 +020018389static void alc663_m51va_unsol_event(struct hda_codec *codec,
18390 unsigned int res)
18391{
18392 switch (res >> 26) {
18393 case ALC880_HP_EVENT:
18394 alc663_m51va_speaker_automute(codec);
18395 break;
18396 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018397 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018398 break;
18399 }
18400}
18401
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018402static void alc663_m51va_setup(struct hda_codec *codec)
18403{
18404 struct alc_spec *spec = codec->spec;
18405 spec->ext_mic.pin = 0x18;
18406 spec->ext_mic.mux_idx = 0;
18407 spec->int_mic.pin = 0x12;
Kailang Yangebb83ee2009-12-17 12:23:00 +010018408 spec->int_mic.mux_idx = 9;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018409 spec->auto_mic = 1;
18410}
18411
Kailang Yang6dda9f42008-05-27 12:05:31 +020018412static void alc663_m51va_inithook(struct hda_codec *codec)
18413{
18414 alc663_m51va_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018415 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018416}
18417
Kailang Yangf1d4e282008-08-26 14:03:29 +020018418/* ***************** Mode1 ******************************/
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018419#define alc663_mode1_unsol_event alc663_m51va_unsol_event
Kailang Yangebb83ee2009-12-17 12:23:00 +010018420
18421static void alc663_mode1_setup(struct hda_codec *codec)
18422{
18423 struct alc_spec *spec = codec->spec;
18424 spec->ext_mic.pin = 0x18;
18425 spec->ext_mic.mux_idx = 0;
18426 spec->int_mic.pin = 0x19;
18427 spec->int_mic.mux_idx = 1;
18428 spec->auto_mic = 1;
18429}
18430
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018431#define alc663_mode1_inithook alc663_m51va_inithook
Kailang Yangf1d4e282008-08-26 14:03:29 +020018432
Kailang Yangf1d4e282008-08-26 14:03:29 +020018433/* ***************** Mode2 ******************************/
18434static void alc662_mode2_unsol_event(struct hda_codec *codec,
18435 unsigned int res)
18436{
18437 switch (res >> 26) {
18438 case ALC880_HP_EVENT:
18439 alc662_f5z_speaker_automute(codec);
18440 break;
18441 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018442 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018443 break;
18444 }
18445}
18446
Kailang Yangebb83ee2009-12-17 12:23:00 +010018447#define alc662_mode2_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018448
Kailang Yangf1d4e282008-08-26 14:03:29 +020018449static void alc662_mode2_inithook(struct hda_codec *codec)
18450{
18451 alc662_f5z_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018452 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018453}
18454/* ***************** Mode3 ******************************/
18455static void alc663_mode3_unsol_event(struct hda_codec *codec,
18456 unsigned int res)
18457{
18458 switch (res >> 26) {
18459 case ALC880_HP_EVENT:
18460 alc663_two_hp_m1_speaker_automute(codec);
18461 break;
18462 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018463 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018464 break;
18465 }
18466}
18467
Kailang Yangebb83ee2009-12-17 12:23:00 +010018468#define alc663_mode3_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018469
Kailang Yangf1d4e282008-08-26 14:03:29 +020018470static void alc663_mode3_inithook(struct hda_codec *codec)
18471{
18472 alc663_two_hp_m1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018473 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018474}
18475/* ***************** Mode4 ******************************/
18476static void alc663_mode4_unsol_event(struct hda_codec *codec,
18477 unsigned int res)
18478{
18479 switch (res >> 26) {
18480 case ALC880_HP_EVENT:
18481 alc663_21jd_two_speaker_automute(codec);
18482 break;
18483 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018484 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018485 break;
18486 }
18487}
18488
Kailang Yangebb83ee2009-12-17 12:23:00 +010018489#define alc663_mode4_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018490
Kailang Yangf1d4e282008-08-26 14:03:29 +020018491static void alc663_mode4_inithook(struct hda_codec *codec)
18492{
18493 alc663_21jd_two_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018494 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018495}
18496/* ***************** Mode5 ******************************/
18497static void alc663_mode5_unsol_event(struct hda_codec *codec,
18498 unsigned int res)
18499{
18500 switch (res >> 26) {
18501 case ALC880_HP_EVENT:
18502 alc663_15jd_two_speaker_automute(codec);
18503 break;
18504 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018505 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018506 break;
18507 }
18508}
18509
Kailang Yangebb83ee2009-12-17 12:23:00 +010018510#define alc663_mode5_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018511
Kailang Yangf1d4e282008-08-26 14:03:29 +020018512static void alc663_mode5_inithook(struct hda_codec *codec)
18513{
18514 alc663_15jd_two_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018515 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018516}
18517/* ***************** Mode6 ******************************/
18518static void alc663_mode6_unsol_event(struct hda_codec *codec,
18519 unsigned int res)
18520{
18521 switch (res >> 26) {
18522 case ALC880_HP_EVENT:
18523 alc663_two_hp_m2_speaker_automute(codec);
18524 break;
18525 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018526 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018527 break;
18528 }
18529}
18530
Kailang Yangebb83ee2009-12-17 12:23:00 +010018531#define alc663_mode6_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018532
Kailang Yangf1d4e282008-08-26 14:03:29 +020018533static void alc663_mode6_inithook(struct hda_codec *codec)
18534{
18535 alc663_two_hp_m2_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018536 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018537}
18538
Kailang Yangebb83ee2009-12-17 12:23:00 +010018539/* ***************** Mode7 ******************************/
18540static void alc663_mode7_unsol_event(struct hda_codec *codec,
18541 unsigned int res)
18542{
18543 switch (res >> 26) {
18544 case ALC880_HP_EVENT:
18545 alc663_two_hp_m7_speaker_automute(codec);
18546 break;
18547 case ALC880_MIC_EVENT:
18548 alc_mic_automute(codec);
18549 break;
18550 }
18551}
18552
18553#define alc663_mode7_setup alc663_mode1_setup
18554
18555static void alc663_mode7_inithook(struct hda_codec *codec)
18556{
18557 alc663_two_hp_m7_speaker_automute(codec);
18558 alc_mic_automute(codec);
18559}
18560
18561/* ***************** Mode8 ******************************/
18562static void alc663_mode8_unsol_event(struct hda_codec *codec,
18563 unsigned int res)
18564{
18565 switch (res >> 26) {
18566 case ALC880_HP_EVENT:
18567 alc663_two_hp_m8_speaker_automute(codec);
18568 break;
18569 case ALC880_MIC_EVENT:
18570 alc_mic_automute(codec);
18571 break;
18572 }
18573}
18574
18575#define alc663_mode8_setup alc663_m51va_setup
18576
18577static void alc663_mode8_inithook(struct hda_codec *codec)
18578{
18579 alc663_two_hp_m8_speaker_automute(codec);
18580 alc_mic_automute(codec);
18581}
18582
Kailang Yang6dda9f42008-05-27 12:05:31 +020018583static void alc663_g71v_hp_automute(struct hda_codec *codec)
18584{
18585 unsigned int present;
18586 unsigned char bits;
18587
Wu Fengguang864f92b2009-11-18 12:38:02 +080018588 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018589 bits = present ? HDA_AMP_MUTE : 0;
18590 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
18591 HDA_AMP_MUTE, bits);
18592 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
18593 HDA_AMP_MUTE, bits);
18594}
18595
18596static void alc663_g71v_front_automute(struct hda_codec *codec)
18597{
18598 unsigned int present;
18599 unsigned char bits;
18600
Wu Fengguang864f92b2009-11-18 12:38:02 +080018601 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018602 bits = present ? HDA_AMP_MUTE : 0;
18603 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
18604 HDA_AMP_MUTE, bits);
18605}
18606
18607static void alc663_g71v_unsol_event(struct hda_codec *codec,
18608 unsigned int res)
18609{
18610 switch (res >> 26) {
18611 case ALC880_HP_EVENT:
18612 alc663_g71v_hp_automute(codec);
18613 break;
18614 case ALC880_FRONT_EVENT:
18615 alc663_g71v_front_automute(codec);
18616 break;
18617 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018618 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018619 break;
18620 }
18621}
18622
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018623#define alc663_g71v_setup alc663_m51va_setup
18624
Kailang Yang6dda9f42008-05-27 12:05:31 +020018625static void alc663_g71v_inithook(struct hda_codec *codec)
18626{
18627 alc663_g71v_front_automute(codec);
18628 alc663_g71v_hp_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018629 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018630}
18631
18632static void alc663_g50v_unsol_event(struct hda_codec *codec,
18633 unsigned int res)
18634{
18635 switch (res >> 26) {
18636 case ALC880_HP_EVENT:
18637 alc663_m51va_speaker_automute(codec);
18638 break;
18639 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018640 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018641 break;
18642 }
18643}
18644
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018645#define alc663_g50v_setup alc663_m51va_setup
18646
Kailang Yang6dda9f42008-05-27 12:05:31 +020018647static void alc663_g50v_inithook(struct hda_codec *codec)
18648{
18649 alc663_m51va_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018650 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018651}
18652
Kailang Yangf1d4e282008-08-26 14:03:29 +020018653static struct snd_kcontrol_new alc662_ecs_mixer[] = {
18654 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020018655 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018656
David Henningsson5f99f862011-01-04 15:24:24 +010018657 HDA_CODEC_VOLUME("Mic/LineIn Boost Volume", 0x18, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010018658 HDA_CODEC_VOLUME("Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
18659 HDA_CODEC_MUTE("Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020018660
David Henningsson5f99f862011-01-04 15:24:24 +010018661 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010018662 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
18663 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020018664 { } /* end */
18665};
18666
Chris Pockelé9541ba12009-05-12 08:08:53 +020018667static struct snd_kcontrol_new alc272_nc10_mixer[] = {
18668 /* Master Playback automatically created from Speaker and Headphone */
18669 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
18670 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
18671 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
18672 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
18673
David Henningsson8607f7c2010-12-20 14:43:54 +010018674 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
18675 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010018676 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Chris Pockelé9541ba12009-05-12 08:08:53 +020018677
David Henningsson28c4edb2010-12-20 14:24:29 +010018678 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
18679 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010018680 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Chris Pockelé9541ba12009-05-12 08:08:53 +020018681 { } /* end */
18682};
18683
Takashi Iwaicb53c622007-08-10 17:21:45 +020018684#ifdef CONFIG_SND_HDA_POWER_SAVE
18685#define alc662_loopbacks alc880_loopbacks
18686#endif
18687
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018688
Sasha Alexandrdef319f2009-06-16 16:00:15 -040018689/* pcm configuration: identical with ALC880 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018690#define alc662_pcm_analog_playback alc880_pcm_analog_playback
18691#define alc662_pcm_analog_capture alc880_pcm_analog_capture
18692#define alc662_pcm_digital_playback alc880_pcm_digital_playback
18693#define alc662_pcm_digital_capture alc880_pcm_digital_capture
18694
18695/*
18696 * configuration and preset
18697 */
Takashi Iwaiea734962011-01-17 11:29:34 +010018698static const char * const alc662_models[ALC662_MODEL_LAST] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018699 [ALC662_3ST_2ch_DIG] = "3stack-dig",
18700 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
18701 [ALC662_3ST_6ch] = "3stack-6ch",
18702 [ALC662_5ST_DIG] = "6stack-dig",
18703 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020018704 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010018705 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangf1d4e282008-08-26 14:03:29 +020018706 [ALC662_ECS] = "ecs",
Kailang Yang6dda9f42008-05-27 12:05:31 +020018707 [ALC663_ASUS_M51VA] = "m51va",
18708 [ALC663_ASUS_G71V] = "g71v",
18709 [ALC663_ASUS_H13] = "h13",
18710 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangf1d4e282008-08-26 14:03:29 +020018711 [ALC663_ASUS_MODE1] = "asus-mode1",
18712 [ALC662_ASUS_MODE2] = "asus-mode2",
18713 [ALC663_ASUS_MODE3] = "asus-mode3",
18714 [ALC663_ASUS_MODE4] = "asus-mode4",
18715 [ALC663_ASUS_MODE5] = "asus-mode5",
18716 [ALC663_ASUS_MODE6] = "asus-mode6",
Kailang Yangebb83ee2009-12-17 12:23:00 +010018717 [ALC663_ASUS_MODE7] = "asus-mode7",
18718 [ALC663_ASUS_MODE8] = "asus-mode8",
Takashi Iwai01f2bd42009-05-11 08:12:43 +020018719 [ALC272_DELL] = "dell",
18720 [ALC272_DELL_ZM1] = "dell-zm1",
Chris Pockelé9541ba12009-05-12 08:08:53 +020018721 [ALC272_SAMSUNG_NC10] = "samsung-nc10",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018722 [ALC662_AUTO] = "auto",
18723};
18724
18725static struct snd_pci_quirk alc662_cfg_tbl[] = {
Takashi Iwaidea0a502009-02-09 17:14:52 +010018726 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
Kailang Yang622e84c2009-04-21 07:39:04 +020018727 SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
18728 SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018729 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
18730 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
Kailang Yangcec27c82010-02-04 14:18:18 +010018731 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018732 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
18733 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
18734 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
18735 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018736 SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC663_ASUS_MODE1),
18737 SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018738 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018739 SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC663_ASUS_MODE7),
18740 SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC663_ASUS_MODE7),
18741 SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC663_ASUS_MODE8),
18742 SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC663_ASUS_MODE3),
18743 SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018744 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018745 SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_ASUS_MODE2),
18746 SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018747 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
18748 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
18749 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
18750 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018751 SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020018752 SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3),
18753 SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA),
18754 SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018755 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
18756 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
18757 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
18758 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018759 SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018760 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
18761 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang6dda9f42008-05-27 12:05:31 +020018762 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018763 /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/
18764 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
18765 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020018766 SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1),
Kailang Yangcec27c82010-02-04 14:18:18 +010018767 SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020018768 SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1),
18769 SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018770 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
18771 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
18772 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018773 SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018774 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
18775 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020018776 SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018777 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
Kailang Yang80ffe862008-10-15 11:23:27 +020018778 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018779 /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/
18780 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
18781 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018782 SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018783 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
18784 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010018785 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020018786 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010018787 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018788 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
Herton Ronaldo Krzesinski95fe5f22008-09-26 23:48:45 -030018789 SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
18790 ALC662_3ST_6ch_DIG),
Takashi Iwai4dee8ba2010-01-13 17:20:08 +010018791 SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO),
Chris Pockelé9541ba12009-05-12 08:08:53 +020018792 SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
Herton Ronaldo Krzesinskicb559742008-09-26 23:47:45 -030018793 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
18794 ALC662_3ST_6ch_DIG),
Kailang Yang6227cdc2010-02-25 08:36:52 +010018795 SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13),
Vedran Miletic19c009a2008-09-29 20:29:25 +020018796 SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
Takashi Iwai5bd37292009-04-21 18:36:30 +020018797 SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018798 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Takashi Iwai238713d2008-10-05 10:57:39 +020018799 SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
Vedran Miletic19c009a2008-09-29 20:29:25 +020018800 ALC662_3ST_6ch_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018801 SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
18802 ALC663_ASUS_H13),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018803 {}
18804};
18805
18806static struct alc_config_preset alc662_presets[] = {
18807 [ALC662_3ST_2ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018808 .mixers = { alc662_3ST_2ch_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018809 .init_verbs = { alc662_init_verbs },
18810 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18811 .dac_nids = alc662_dac_nids,
18812 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018813 .dig_in_nid = ALC662_DIGIN_NID,
18814 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18815 .channel_mode = alc662_3ST_2ch_modes,
18816 .input_mux = &alc662_capture_source,
18817 },
18818 [ALC662_3ST_6ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018819 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018820 .init_verbs = { alc662_init_verbs },
18821 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18822 .dac_nids = alc662_dac_nids,
18823 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018824 .dig_in_nid = ALC662_DIGIN_NID,
18825 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18826 .channel_mode = alc662_3ST_6ch_modes,
18827 .need_dac_fix = 1,
18828 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018829 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018830 [ALC662_3ST_6ch] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018831 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018832 .init_verbs = { alc662_init_verbs },
18833 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18834 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018835 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18836 .channel_mode = alc662_3ST_6ch_modes,
18837 .need_dac_fix = 1,
18838 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018839 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018840 [ALC662_5ST_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018841 .mixers = { alc662_base_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018842 .init_verbs = { alc662_init_verbs },
18843 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18844 .dac_nids = alc662_dac_nids,
18845 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018846 .dig_in_nid = ALC662_DIGIN_NID,
18847 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
18848 .channel_mode = alc662_5stack_modes,
18849 .input_mux = &alc662_capture_source,
18850 },
18851 [ALC662_LENOVO_101E] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018852 .mixers = { alc662_lenovo_101e_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018853 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
18854 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18855 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018856 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18857 .channel_mode = alc662_3ST_2ch_modes,
18858 .input_mux = &alc662_lenovo_101e_capture_source,
18859 .unsol_event = alc662_lenovo_101e_unsol_event,
18860 .init_hook = alc662_lenovo_101e_all_automute,
18861 },
Kailang Yang291702f2007-10-16 14:28:03 +020018862 [ALC662_ASUS_EEEPC_P701] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018863 .mixers = { alc662_eeepc_p701_mixer },
Kailang Yang291702f2007-10-16 14:28:03 +020018864 .init_verbs = { alc662_init_verbs,
18865 alc662_eeepc_sue_init_verbs },
18866 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18867 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020018868 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18869 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang291702f2007-10-16 14:28:03 +020018870 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018871 .setup = alc662_eeepc_setup,
Kailang Yang291702f2007-10-16 14:28:03 +020018872 .init_hook = alc662_eeepc_inithook,
18873 },
Kailang Yang8c427222008-01-10 13:03:59 +010018874 [ALC662_ASUS_EEEPC_EP20] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018875 .mixers = { alc662_eeepc_ep20_mixer,
Kailang Yang8c427222008-01-10 13:03:59 +010018876 alc662_chmode_mixer },
18877 .init_verbs = { alc662_init_verbs,
18878 alc662_eeepc_ep20_sue_init_verbs },
18879 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18880 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010018881 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18882 .channel_mode = alc662_3ST_6ch_modes,
18883 .input_mux = &alc662_lenovo_101e_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020018884 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018885 .setup = alc662_eeepc_ep20_setup,
Kailang Yang8c427222008-01-10 13:03:59 +010018886 .init_hook = alc662_eeepc_ep20_inithook,
18887 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018888 [ALC662_ECS] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018889 .mixers = { alc662_ecs_mixer },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018890 .init_verbs = { alc662_init_verbs,
18891 alc662_ecs_init_verbs },
18892 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18893 .dac_nids = alc662_dac_nids,
18894 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18895 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018896 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018897 .setup = alc662_eeepc_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018898 .init_hook = alc662_eeepc_inithook,
18899 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018900 [ALC663_ASUS_M51VA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018901 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018902 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
18903 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18904 .dac_nids = alc662_dac_nids,
18905 .dig_out_nid = ALC662_DIGOUT_NID,
18906 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18907 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018908 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018909 .setup = alc663_m51va_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018910 .init_hook = alc663_m51va_inithook,
18911 },
18912 [ALC663_ASUS_G71V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018913 .mixers = { alc663_g71v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018914 .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
18915 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18916 .dac_nids = alc662_dac_nids,
18917 .dig_out_nid = ALC662_DIGOUT_NID,
18918 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18919 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018920 .unsol_event = alc663_g71v_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018921 .setup = alc663_g71v_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018922 .init_hook = alc663_g71v_inithook,
18923 },
18924 [ALC663_ASUS_H13] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018925 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018926 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
18927 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18928 .dac_nids = alc662_dac_nids,
18929 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18930 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018931 .unsol_event = alc663_m51va_unsol_event,
18932 .init_hook = alc663_m51va_inithook,
18933 },
18934 [ALC663_ASUS_G50V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018935 .mixers = { alc663_g50v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018936 .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
18937 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18938 .dac_nids = alc662_dac_nids,
18939 .dig_out_nid = ALC662_DIGOUT_NID,
18940 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18941 .channel_mode = alc662_3ST_6ch_modes,
18942 .input_mux = &alc663_capture_source,
18943 .unsol_event = alc663_g50v_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018944 .setup = alc663_g50v_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018945 .init_hook = alc663_g50v_inithook,
18946 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018947 [ALC663_ASUS_MODE1] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018948 .mixers = { alc663_m51va_mixer },
18949 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018950 .init_verbs = { alc662_init_verbs,
18951 alc663_21jd_amic_init_verbs },
18952 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18953 .hp_nid = 0x03,
18954 .dac_nids = alc662_dac_nids,
18955 .dig_out_nid = ALC662_DIGOUT_NID,
18956 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18957 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018958 .unsol_event = alc663_mode1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018959 .setup = alc663_mode1_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018960 .init_hook = alc663_mode1_inithook,
18961 },
18962 [ALC662_ASUS_MODE2] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018963 .mixers = { alc662_1bjd_mixer },
18964 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018965 .init_verbs = { alc662_init_verbs,
18966 alc662_1bjd_amic_init_verbs },
18967 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18968 .dac_nids = alc662_dac_nids,
18969 .dig_out_nid = ALC662_DIGOUT_NID,
18970 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18971 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018972 .unsol_event = alc662_mode2_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018973 .setup = alc662_mode2_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018974 .init_hook = alc662_mode2_inithook,
18975 },
18976 [ALC663_ASUS_MODE3] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018977 .mixers = { alc663_two_hp_m1_mixer },
18978 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018979 .init_verbs = { alc662_init_verbs,
18980 alc663_two_hp_amic_m1_init_verbs },
18981 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18982 .hp_nid = 0x03,
18983 .dac_nids = alc662_dac_nids,
18984 .dig_out_nid = ALC662_DIGOUT_NID,
18985 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18986 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018987 .unsol_event = alc663_mode3_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018988 .setup = alc663_mode3_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018989 .init_hook = alc663_mode3_inithook,
18990 },
18991 [ALC663_ASUS_MODE4] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018992 .mixers = { alc663_asus_21jd_clfe_mixer },
18993 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018994 .init_verbs = { alc662_init_verbs,
18995 alc663_21jd_amic_init_verbs},
18996 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18997 .hp_nid = 0x03,
18998 .dac_nids = alc662_dac_nids,
18999 .dig_out_nid = ALC662_DIGOUT_NID,
19000 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
19001 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020019002 .unsol_event = alc663_mode4_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020019003 .setup = alc663_mode4_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020019004 .init_hook = alc663_mode4_inithook,
19005 },
19006 [ALC663_ASUS_MODE5] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010019007 .mixers = { alc663_asus_15jd_clfe_mixer },
19008 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020019009 .init_verbs = { alc662_init_verbs,
19010 alc663_15jd_amic_init_verbs },
19011 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
19012 .hp_nid = 0x03,
19013 .dac_nids = alc662_dac_nids,
19014 .dig_out_nid = ALC662_DIGOUT_NID,
19015 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
19016 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020019017 .unsol_event = alc663_mode5_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020019018 .setup = alc663_mode5_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020019019 .init_hook = alc663_mode5_inithook,
19020 },
19021 [ALC663_ASUS_MODE6] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010019022 .mixers = { alc663_two_hp_m2_mixer },
19023 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020019024 .init_verbs = { alc662_init_verbs,
19025 alc663_two_hp_amic_m2_init_verbs },
19026 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
19027 .hp_nid = 0x03,
19028 .dac_nids = alc662_dac_nids,
19029 .dig_out_nid = ALC662_DIGOUT_NID,
19030 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
19031 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020019032 .unsol_event = alc663_mode6_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020019033 .setup = alc663_mode6_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020019034 .init_hook = alc663_mode6_inithook,
19035 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010019036 [ALC663_ASUS_MODE7] = {
19037 .mixers = { alc663_mode7_mixer },
19038 .cap_mixer = alc662_auto_capture_mixer,
19039 .init_verbs = { alc662_init_verbs,
19040 alc663_mode7_init_verbs },
19041 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
19042 .hp_nid = 0x03,
19043 .dac_nids = alc662_dac_nids,
19044 .dig_out_nid = ALC662_DIGOUT_NID,
19045 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
19046 .channel_mode = alc662_3ST_2ch_modes,
19047 .unsol_event = alc663_mode7_unsol_event,
19048 .setup = alc663_mode7_setup,
19049 .init_hook = alc663_mode7_inithook,
19050 },
19051 [ALC663_ASUS_MODE8] = {
19052 .mixers = { alc663_mode8_mixer },
19053 .cap_mixer = alc662_auto_capture_mixer,
19054 .init_verbs = { alc662_init_verbs,
19055 alc663_mode8_init_verbs },
19056 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
19057 .hp_nid = 0x03,
19058 .dac_nids = alc662_dac_nids,
19059 .dig_out_nid = ALC662_DIGOUT_NID,
19060 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
19061 .channel_mode = alc662_3ST_2ch_modes,
19062 .unsol_event = alc663_mode8_unsol_event,
19063 .setup = alc663_mode8_setup,
19064 .init_hook = alc663_mode8_inithook,
19065 },
Kailang Yang622e84c2009-04-21 07:39:04 +020019066 [ALC272_DELL] = {
19067 .mixers = { alc663_m51va_mixer },
19068 .cap_mixer = alc272_auto_capture_mixer,
19069 .init_verbs = { alc662_init_verbs, alc272_dell_init_verbs },
19070 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
19071 .dac_nids = alc662_dac_nids,
19072 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
19073 .adc_nids = alc272_adc_nids,
19074 .num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
19075 .capsrc_nids = alc272_capsrc_nids,
19076 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang622e84c2009-04-21 07:39:04 +020019077 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020019078 .setup = alc663_m51va_setup,
Kailang Yang622e84c2009-04-21 07:39:04 +020019079 .init_hook = alc663_m51va_inithook,
19080 },
19081 [ALC272_DELL_ZM1] = {
19082 .mixers = { alc663_m51va_mixer },
19083 .cap_mixer = alc662_auto_capture_mixer,
19084 .init_verbs = { alc662_init_verbs, alc272_dell_zm1_init_verbs },
19085 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
19086 .dac_nids = alc662_dac_nids,
19087 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
19088 .adc_nids = alc662_adc_nids,
Takashi Iwaib59bdf32009-08-11 09:47:30 +020019089 .num_adc_nids = 1,
Kailang Yang622e84c2009-04-21 07:39:04 +020019090 .capsrc_nids = alc662_capsrc_nids,
19091 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang622e84c2009-04-21 07:39:04 +020019092 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020019093 .setup = alc663_m51va_setup,
Kailang Yang622e84c2009-04-21 07:39:04 +020019094 .init_hook = alc663_m51va_inithook,
19095 },
Chris Pockelé9541ba12009-05-12 08:08:53 +020019096 [ALC272_SAMSUNG_NC10] = {
19097 .mixers = { alc272_nc10_mixer },
19098 .init_verbs = { alc662_init_verbs,
19099 alc663_21jd_amic_init_verbs },
19100 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
19101 .dac_nids = alc272_dac_nids,
19102 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
19103 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020019104 /*.input_mux = &alc272_nc10_capture_source,*/
Chris Pockelé9541ba12009-05-12 08:08:53 +020019105 .unsol_event = alc663_mode4_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020019106 .setup = alc663_mode4_setup,
Chris Pockelé9541ba12009-05-12 08:08:53 +020019107 .init_hook = alc663_mode4_inithook,
19108 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019109};
19110
19111
19112/*
19113 * BIOS auto configuration
19114 */
19115
Takashi Iwai7085ec12009-10-02 09:03:58 +020019116/* convert from MIX nid to DAC */
19117static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid)
19118{
19119 if (nid == 0x0f)
19120 return 0x02;
19121 else if (nid >= 0x0c && nid <= 0x0e)
19122 return nid - 0x0c + 0x02;
David Henningssoncc1c4522010-11-24 14:17:47 +010019123 else if (nid == 0x26) /* ALC887-VD has this DAC too */
19124 return 0x25;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019125 else
19126 return 0;
19127}
19128
19129/* get MIX nid connected to the given pin targeted to DAC */
19130static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
19131 hda_nid_t dac)
19132{
David Henningssoncc1c4522010-11-24 14:17:47 +010019133 hda_nid_t mix[5];
Takashi Iwai7085ec12009-10-02 09:03:58 +020019134 int i, num;
19135
19136 num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
19137 for (i = 0; i < num; i++) {
19138 if (alc662_mix_to_dac(mix[i]) == dac)
19139 return mix[i];
19140 }
19141 return 0;
19142}
19143
19144/* look for an empty DAC slot */
19145static hda_nid_t alc662_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
19146{
19147 struct alc_spec *spec = codec->spec;
19148 hda_nid_t srcs[5];
19149 int i, j, num;
19150
19151 num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
19152 if (num < 0)
19153 return 0;
19154 for (i = 0; i < num; i++) {
19155 hda_nid_t nid = alc662_mix_to_dac(srcs[i]);
19156 if (!nid)
19157 continue;
19158 for (j = 0; j < spec->multiout.num_dacs; j++)
19159 if (spec->multiout.dac_nids[j] == nid)
19160 break;
19161 if (j >= spec->multiout.num_dacs)
19162 return nid;
19163 }
19164 return 0;
19165}
19166
19167/* fill in the dac_nids table from the parsed pin configuration */
19168static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
19169 const struct auto_pin_cfg *cfg)
19170{
19171 struct alc_spec *spec = codec->spec;
19172 int i;
19173 hda_nid_t dac;
19174
19175 spec->multiout.dac_nids = spec->private_dac_nids;
19176 for (i = 0; i < cfg->line_outs; i++) {
19177 dac = alc662_look_for_dac(codec, cfg->line_out_pins[i]);
19178 if (!dac)
19179 continue;
19180 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
19181 }
19182 return 0;
19183}
19184
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019185static inline int __alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
19186 hda_nid_t nid, int idx, unsigned int chs)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019187{
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019188 return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019189 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
19190}
19191
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019192static inline int __alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
19193 hda_nid_t nid, int idx, unsigned int chs)
Takashi Iwai7085ec12009-10-02 09:03:58 +020019194{
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019195 return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019196 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
19197}
19198
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019199#define alc662_add_vol_ctl(spec, pfx, nid, chs) \
19200 __alc662_add_vol_ctl(spec, pfx, nid, 0, chs)
19201#define alc662_add_sw_ctl(spec, pfx, nid, chs) \
19202 __alc662_add_sw_ctl(spec, pfx, nid, 0, chs)
Takashi Iwai7085ec12009-10-02 09:03:58 +020019203#define alc662_add_stereo_vol(spec, pfx, nid) \
19204 alc662_add_vol_ctl(spec, pfx, nid, 3)
19205#define alc662_add_stereo_sw(spec, pfx, nid) \
19206 alc662_add_sw_ctl(spec, pfx, nid, 3)
19207
19208/* add playback controls from the parsed DAC table */
19209static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
19210 const struct auto_pin_cfg *cfg)
19211{
19212 struct alc_spec *spec = codec->spec;
Takashi Iwaiea734962011-01-17 11:29:34 +010019213 static const char * const chname[4] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019214 "Front", "Surround", NULL /*CLFE*/, "Side"
19215 };
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019216 const char *pfx = alc_get_line_out_pfx(cfg, true);
Takashi Iwai7085ec12009-10-02 09:03:58 +020019217 hda_nid_t nid, mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019218 int i, err;
19219
19220 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020019221 nid = spec->multiout.dac_nids[i];
19222 if (!nid)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019223 continue;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019224 mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid);
19225 if (!mix)
19226 continue;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019227 if (!pfx && i == 2) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019228 /* Center/LFE */
Takashi Iwai7085ec12009-10-02 09:03:58 +020019229 err = alc662_add_vol_ctl(spec, "Center", nid, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019230 if (err < 0)
19231 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019232 err = alc662_add_vol_ctl(spec, "LFE", nid, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019233 if (err < 0)
19234 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019235 err = alc662_add_sw_ctl(spec, "Center", mix, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019236 if (err < 0)
19237 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019238 err = alc662_add_sw_ctl(spec, "LFE", mix, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019239 if (err < 0)
19240 return err;
19241 } else {
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019242 const char *name = pfx;
19243 if (!name)
19244 name = chname[i];
19245 err = __alc662_add_vol_ctl(spec, name, nid, i, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019246 if (err < 0)
19247 return err;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019248 err = __alc662_add_sw_ctl(spec, name, mix, i, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019249 if (err < 0)
19250 return err;
19251 }
19252 }
19253 return 0;
19254}
19255
19256/* add playback controls for speaker and HP outputs */
Takashi Iwai7085ec12009-10-02 09:03:58 +020019257/* return DAC nid if any new DAC is assigned */
19258static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019259 const char *pfx)
19260{
Takashi Iwai7085ec12009-10-02 09:03:58 +020019261 struct alc_spec *spec = codec->spec;
19262 hda_nid_t nid, mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019263 int err;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019264
19265 if (!pin)
19266 return 0;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019267 nid = alc662_look_for_dac(codec, pin);
19268 if (!nid) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020019269 /* the corresponding DAC is already occupied */
19270 if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
19271 return 0; /* no way */
19272 /* create a switch only */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020019273 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019274 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
19275 }
19276
19277 mix = alc662_dac_to_mix(codec, pin, nid);
19278 if (!mix)
19279 return 0;
19280 err = alc662_add_vol_ctl(spec, pfx, nid, 3);
19281 if (err < 0)
Takashi Iwai24fb9172008-09-02 14:48:20 +020019282 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019283 err = alc662_add_sw_ctl(spec, pfx, mix, 3);
19284 if (err < 0)
19285 return err;
19286 return nid;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019287}
19288
19289/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020019290#define alc662_auto_create_input_ctls \
Takashi Iwai4b7348a2009-10-14 18:25:23 +020019291 alc882_auto_create_input_ctls
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019292
19293static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
19294 hda_nid_t nid, int pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019295 hda_nid_t dac)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019296{
Takashi Iwai7085ec12009-10-02 09:03:58 +020019297 int i, num;
Takashi Iwaice503f32010-07-30 10:37:29 +020019298 hda_nid_t srcs[HDA_MAX_CONNECTIONS];
Takashi Iwai7085ec12009-10-02 09:03:58 +020019299
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019300 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019301 /* need the manual connection? */
Takashi Iwai7085ec12009-10-02 09:03:58 +020019302 num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
19303 if (num <= 1)
19304 return;
19305 for (i = 0; i < num; i++) {
19306 if (alc662_mix_to_dac(srcs[i]) != dac)
19307 continue;
19308 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
19309 return;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019310 }
19311}
19312
19313static void alc662_auto_init_multi_out(struct hda_codec *codec)
19314{
19315 struct alc_spec *spec = codec->spec;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019316 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019317 int i;
19318
19319 for (i = 0; i <= HDA_SIDE; i++) {
19320 hda_nid_t nid = spec->autocfg.line_out_pins[i];
19321 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020019322 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019323 spec->multiout.dac_nids[i]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019324 }
19325}
19326
19327static void alc662_auto_init_hp_out(struct hda_codec *codec)
19328{
19329 struct alc_spec *spec = codec->spec;
19330 hda_nid_t pin;
19331
19332 pin = spec->autocfg.hp_pins[0];
Takashi Iwai7085ec12009-10-02 09:03:58 +020019333 if (pin)
19334 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP,
19335 spec->multiout.hp_nid);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019336 pin = spec->autocfg.speaker_pins[0];
19337 if (pin)
Takashi Iwai7085ec12009-10-02 09:03:58 +020019338 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT,
19339 spec->multiout.extra_out_nid[0]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019340}
19341
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019342#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
19343
19344static void alc662_auto_init_analog_input(struct hda_codec *codec)
19345{
19346 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019347 struct auto_pin_cfg *cfg = &spec->autocfg;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019348 int i;
19349
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019350 for (i = 0; i < cfg->num_inputs; i++) {
19351 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +020019352 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai30ea0982010-09-16 18:47:56 +020019353 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwai52ca15b2009-03-23 12:51:55 +010019354 if (nid != ALC662_PIN_CD_NID &&
Takashi Iwaie82c0252009-03-23 15:17:38 +010019355 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019356 snd_hda_codec_write(codec, nid, 0,
19357 AC_VERB_SET_AMP_GAIN_MUTE,
19358 AMP_OUT_MUTE);
19359 }
19360 }
19361}
19362
Takashi Iwaif511b012008-08-15 16:46:42 +020019363#define alc662_auto_init_input_src alc882_auto_init_input_src
19364
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019365static int alc662_parse_auto_config(struct hda_codec *codec)
19366{
19367 struct alc_spec *spec = codec->spec;
19368 int err;
19369 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
19370
19371 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
19372 alc662_ignore);
19373 if (err < 0)
19374 return err;
19375 if (!spec->autocfg.line_outs)
19376 return 0; /* can't find valid BIOS pin config */
19377
Takashi Iwai7085ec12009-10-02 09:03:58 +020019378 err = alc662_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019379 if (err < 0)
19380 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019381 err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019382 if (err < 0)
19383 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019384 err = alc662_auto_create_extra_out(codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019385 spec->autocfg.speaker_pins[0],
19386 "Speaker");
19387 if (err < 0)
19388 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019389 if (err)
19390 spec->multiout.extra_out_nid[0] = err;
19391 err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019392 "Headphone");
19393 if (err < 0)
19394 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019395 if (err)
19396 spec->multiout.hp_nid = err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020019397 err = alc662_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019398 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019399 return err;
19400
19401 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
19402
Takashi Iwai757899a2010-07-30 10:48:14 +020019403 alc_auto_parse_digital(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019404
Takashi Iwai603c4012008-07-30 15:01:44 +020019405 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010019406 add_mixer(spec, spec->kctls.list);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019407
19408 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020019409 spec->input_mux = &spec->private_imux[0];
Kailang Yangea1fb292008-08-26 12:58:38 +020019410
Kailang Yangcec27c82010-02-04 14:18:18 +010019411 add_verb(spec, alc662_init_verbs);
19412 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019413 codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
Kailang Yangcec27c82010-02-04 14:18:18 +010019414 add_verb(spec, alc663_init_verbs);
19415
19416 if (codec->vendor_id == 0x10ec0272)
19417 add_verb(spec, alc272_init_verbs);
Takashi Iwaiee979a142008-09-02 15:42:20 +020019418
19419 err = alc_auto_add_mic_boost(codec);
19420 if (err < 0)
19421 return err;
19422
Kailang Yang6227cdc2010-02-25 08:36:52 +010019423 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
19424 codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
19425 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0x21);
19426 else
19427 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020019428
Takashi Iwai8c872862007-06-19 12:11:16 +020019429 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019430}
19431
19432/* additional initialization for auto-configuration model */
19433static void alc662_auto_init(struct hda_codec *codec)
19434{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019435 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019436 alc662_auto_init_multi_out(codec);
19437 alc662_auto_init_hp_out(codec);
19438 alc662_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020019439 alc662_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020019440 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019441 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020019442 alc_inithook(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019443}
19444
Todd Broch6be79482010-12-07 16:51:05 -080019445static void alc272_fixup_mario(struct hda_codec *codec,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019446 const struct alc_fixup *fix, int action)
Takashi Iwai6fc398c2011-01-13 14:36:37 +010019447{
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019448 if (action != ALC_FIXUP_ACT_PROBE)
Takashi Iwai6fc398c2011-01-13 14:36:37 +010019449 return;
Todd Broch6be79482010-12-07 16:51:05 -080019450 if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT,
19451 (0x3b << AC_AMPCAP_OFFSET_SHIFT) |
19452 (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) |
19453 (0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) |
19454 (0 << AC_AMPCAP_MUTE_SHIFT)))
19455 printk(KERN_WARNING
19456 "hda_codec: failed to override amp caps for NID 0x2\n");
19457}
19458
David Henningsson6cb3b702010-09-09 08:51:44 +020019459enum {
Daniel T Chen2df03512010-10-10 22:39:28 -040019460 ALC662_FIXUP_ASPIRE,
David Henningsson6cb3b702010-09-09 08:51:44 +020019461 ALC662_FIXUP_IDEAPAD,
Todd Broch6be79482010-12-07 16:51:05 -080019462 ALC272_FIXUP_MARIO,
Anisse Astierd2ebd472011-01-20 12:36:21 +010019463 ALC662_FIXUP_CZC_P10T,
David Henningsson6cb3b702010-09-09 08:51:44 +020019464};
19465
19466static const struct alc_fixup alc662_fixups[] = {
Daniel T Chen2df03512010-10-10 22:39:28 -040019467 [ALC662_FIXUP_ASPIRE] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019468 .type = ALC_FIXUP_PINS,
19469 .v.pins = (const struct alc_pincfg[]) {
Daniel T Chen2df03512010-10-10 22:39:28 -040019470 { 0x15, 0x99130112 }, /* subwoofer */
19471 { }
19472 }
19473 },
David Henningsson6cb3b702010-09-09 08:51:44 +020019474 [ALC662_FIXUP_IDEAPAD] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019475 .type = ALC_FIXUP_PINS,
19476 .v.pins = (const struct alc_pincfg[]) {
David Henningsson6cb3b702010-09-09 08:51:44 +020019477 { 0x17, 0x99130112 }, /* subwoofer */
19478 { }
19479 }
19480 },
Todd Broch6be79482010-12-07 16:51:05 -080019481 [ALC272_FIXUP_MARIO] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019482 .type = ALC_FIXUP_FUNC,
19483 .v.func = alc272_fixup_mario,
Anisse Astierd2ebd472011-01-20 12:36:21 +010019484 },
19485 [ALC662_FIXUP_CZC_P10T] = {
19486 .type = ALC_FIXUP_VERBS,
19487 .v.verbs = (const struct hda_verb[]) {
19488 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
19489 {}
19490 }
19491 },
David Henningsson6cb3b702010-09-09 08:51:44 +020019492};
19493
19494static struct snd_pci_quirk alc662_fixup_tbl[] = {
Daniel T Chen2df03512010-10-10 22:39:28 -040019495 SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
Daniel T Chena0e90ac2010-11-20 10:20:35 -050019496 SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
Valentine Sinitsynd4118582010-10-01 22:24:08 +060019497 SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
David Henningsson6cb3b702010-09-09 08:51:44 +020019498 SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
Anisse Astierd2ebd472011-01-20 12:36:21 +010019499 SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
David Henningsson6cb3b702010-09-09 08:51:44 +020019500 {}
19501};
19502
Todd Broch6be79482010-12-07 16:51:05 -080019503static const struct alc_model_fixup alc662_fixup_models[] = {
19504 {.id = ALC272_FIXUP_MARIO, .name = "mario"},
19505 {}
19506};
David Henningsson6cb3b702010-09-09 08:51:44 +020019507
19508
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019509static int patch_alc662(struct hda_codec *codec)
19510{
19511 struct alc_spec *spec;
19512 int err, board_config;
Kailang Yang693194f2010-10-21 08:51:48 +020019513 int coef;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019514
19515 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
19516 if (!spec)
19517 return -ENOMEM;
19518
19519 codec->spec = spec;
19520
Kailang Yangda00c242010-03-19 11:23:45 +010019521 alc_auto_parse_customize_define(codec);
19522
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020019523 alc_fix_pll_init(codec, 0x20, 0x04, 15);
19524
Kailang Yang693194f2010-10-21 08:51:48 +020019525 coef = alc_read_coef_idx(codec, 0);
19526 if (coef == 0x8020 || coef == 0x8011)
Kailang Yangc027ddc2010-03-19 11:33:06 +010019527 alc_codec_rename(codec, "ALC661");
Kailang Yang693194f2010-10-21 08:51:48 +020019528 else if (coef & (1 << 14) &&
19529 codec->bus->pci->subsystem_vendor == 0x1025 &&
19530 spec->cdefine.platform_type == 1)
Kailang Yangc027ddc2010-03-19 11:33:06 +010019531 alc_codec_rename(codec, "ALC272X");
Kailang Yang693194f2010-10-21 08:51:48 +020019532 else if (coef == 0x4011)
19533 alc_codec_rename(codec, "ALC656");
Kailang Yang274693f2009-12-03 10:07:50 +010019534
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019535 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
19536 alc662_models,
19537 alc662_cfg_tbl);
19538 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020019539 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
19540 codec->chip_name);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019541 board_config = ALC662_AUTO;
19542 }
19543
19544 if (board_config == ALC662_AUTO) {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019545 alc_pick_fixup(codec, alc662_fixup_models,
19546 alc662_fixup_tbl, alc662_fixups);
19547 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019548 /* automatic parse from the BIOS config */
19549 err = alc662_parse_auto_config(codec);
19550 if (err < 0) {
19551 alc_free(codec);
19552 return err;
Takashi Iwai8c872862007-06-19 12:11:16 +020019553 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019554 printk(KERN_INFO
19555 "hda_codec: Cannot set up configuration "
19556 "from BIOS. Using base mode...\n");
19557 board_config = ALC662_3ST_2ch_DIG;
19558 }
19559 }
19560
Takashi Iwaidc1eae22010-07-29 15:30:02 +020019561 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020019562 err = snd_hda_attach_beep_device(codec, 0x1);
19563 if (err < 0) {
19564 alc_free(codec);
19565 return err;
19566 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090019567 }
19568
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019569 if (board_config != ALC662_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020019570 setup_preset(codec, &alc662_presets[board_config]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019571
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019572 spec->stream_analog_playback = &alc662_pcm_analog_playback;
19573 spec->stream_analog_capture = &alc662_pcm_analog_capture;
19574
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019575 spec->stream_digital_playback = &alc662_pcm_digital_playback;
19576 spec->stream_digital_capture = &alc662_pcm_digital_capture;
19577
Takashi Iwaidd704692009-08-11 08:45:11 +020019578 if (!spec->adc_nids) {
19579 spec->adc_nids = alc662_adc_nids;
19580 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
19581 }
19582 if (!spec->capsrc_nids)
19583 spec->capsrc_nids = alc662_capsrc_nids;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019584
Takashi Iwaif9e336f2008-10-31 16:37:07 +010019585 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020019586 set_capture_mixer(codec);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010019587
Takashi Iwaidc1eae22010-07-29 15:30:02 +020019588 if (has_cdefine_beep(codec)) {
Kailang Yangda00c242010-03-19 11:23:45 +010019589 switch (codec->vendor_id) {
19590 case 0x10ec0662:
19591 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
19592 break;
19593 case 0x10ec0272:
19594 case 0x10ec0663:
19595 case 0x10ec0665:
19596 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
19597 break;
19598 case 0x10ec0273:
19599 set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
19600 break;
19601 }
Kailang Yangcec27c82010-02-04 14:18:18 +010019602 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010019603 spec->vmaster_nid = 0x02;
19604
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019605 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
19606
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019607 codec->patch_ops = alc_patch_ops;
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019608 if (board_config == ALC662_AUTO)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019609 spec->init_hook = alc662_auto_init;
David Henningsson6cb3b702010-09-09 08:51:44 +020019610
Kailang Yangbf1b0222010-10-21 08:49:56 +020019611 alc_init_jacks(codec);
19612
Takashi Iwaicb53c622007-08-10 17:21:45 +020019613#ifdef CONFIG_SND_HDA_POWER_SAVE
19614 if (!spec->loopback.amplist)
19615 spec->loopback.amplist = alc662_loopbacks;
19616#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019617
19618 return 0;
19619}
19620
Kailang Yang274693f2009-12-03 10:07:50 +010019621static int patch_alc888(struct hda_codec *codec)
19622{
19623 if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){
19624 kfree(codec->chip_name);
Kailang Yang01e0f132010-11-22 10:59:36 +010019625 if (codec->vendor_id == 0x10ec0887)
19626 codec->chip_name = kstrdup("ALC887-VD", GFP_KERNEL);
19627 else
19628 codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010019629 if (!codec->chip_name) {
19630 alc_free(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010019631 return -ENOMEM;
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010019632 }
19633 return patch_alc662(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010019634 }
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010019635 return patch_alc882(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010019636}
19637
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019638/*
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019639 * ALC680 support
19640 */
Kailang Yangc69aefa2010-08-17 10:39:22 +020019641#define ALC680_DIGIN_NID ALC880_DIGIN_NID
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019642#define ALC680_DIGOUT_NID ALC880_DIGOUT_NID
19643#define alc680_modes alc260_modes
19644
19645static hda_nid_t alc680_dac_nids[3] = {
19646 /* Lout1, Lout2, hp */
19647 0x02, 0x03, 0x04
19648};
19649
19650static hda_nid_t alc680_adc_nids[3] = {
19651 /* ADC0-2 */
19652 /* DMIC, MIC, Line-in*/
19653 0x07, 0x08, 0x09
19654};
19655
Kailang Yangc69aefa2010-08-17 10:39:22 +020019656/*
19657 * Analog capture ADC cgange
19658 */
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019659static void alc680_rec_autoswitch(struct hda_codec *codec)
19660{
19661 struct alc_spec *spec = codec->spec;
19662 struct auto_pin_cfg *cfg = &spec->autocfg;
19663 int pin_found = 0;
19664 int type_found = AUTO_PIN_LAST;
19665 hda_nid_t nid;
19666 int i;
19667
19668 for (i = 0; i < cfg->num_inputs; i++) {
19669 nid = cfg->inputs[i].pin;
19670 if (!(snd_hda_query_pin_caps(codec, nid) &
19671 AC_PINCAP_PRES_DETECT))
19672 continue;
19673 if (snd_hda_jack_detect(codec, nid)) {
19674 if (cfg->inputs[i].type < type_found) {
19675 type_found = cfg->inputs[i].type;
19676 pin_found = nid;
19677 }
19678 }
19679 }
19680
19681 nid = 0x07;
19682 if (pin_found)
19683 snd_hda_get_connections(codec, pin_found, &nid, 1);
19684
19685 if (nid != spec->cur_adc)
19686 __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
19687 spec->cur_adc = nid;
19688 snd_hda_codec_setup_stream(codec, nid, spec->cur_adc_stream_tag, 0,
19689 spec->cur_adc_format);
19690}
19691
Kailang Yangc69aefa2010-08-17 10:39:22 +020019692static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
19693 struct hda_codec *codec,
19694 unsigned int stream_tag,
19695 unsigned int format,
19696 struct snd_pcm_substream *substream)
19697{
19698 struct alc_spec *spec = codec->spec;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019699
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019700 spec->cur_adc = 0x07;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019701 spec->cur_adc_stream_tag = stream_tag;
19702 spec->cur_adc_format = format;
19703
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019704 alc680_rec_autoswitch(codec);
Kailang Yangc69aefa2010-08-17 10:39:22 +020019705 return 0;
19706}
19707
19708static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
19709 struct hda_codec *codec,
19710 struct snd_pcm_substream *substream)
19711{
19712 snd_hda_codec_cleanup_stream(codec, 0x07);
19713 snd_hda_codec_cleanup_stream(codec, 0x08);
19714 snd_hda_codec_cleanup_stream(codec, 0x09);
19715 return 0;
19716}
19717
19718static struct hda_pcm_stream alc680_pcm_analog_auto_capture = {
19719 .substreams = 1, /* can be overridden */
19720 .channels_min = 2,
19721 .channels_max = 2,
19722 /* NID is set in alc_build_pcms */
19723 .ops = {
19724 .prepare = alc680_capture_pcm_prepare,
19725 .cleanup = alc680_capture_pcm_cleanup
19726 },
19727};
19728
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019729static struct snd_kcontrol_new alc680_base_mixer[] = {
19730 /* output mixer control */
19731 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
19732 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
19733 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT),
19734 HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010019735 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x12, 0, HDA_INPUT),
19736 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
19737 HDA_CODEC_VOLUME("Line In Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019738 { }
19739};
19740
Kailang Yangc69aefa2010-08-17 10:39:22 +020019741static struct hda_bind_ctls alc680_bind_cap_vol = {
19742 .ops = &snd_hda_bind_vol,
19743 .values = {
19744 HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
19745 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
19746 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
19747 0
19748 },
19749};
19750
19751static struct hda_bind_ctls alc680_bind_cap_switch = {
19752 .ops = &snd_hda_bind_sw,
19753 .values = {
19754 HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
19755 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
19756 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
19757 0
19758 },
19759};
19760
19761static struct snd_kcontrol_new alc680_master_capture_mixer[] = {
19762 HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol),
19763 HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch),
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019764 { } /* end */
19765};
19766
19767/*
19768 * generic initialization of ADC, input mixers and output mixers
19769 */
19770static struct hda_verb alc680_init_verbs[] = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019771 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
19772 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
19773 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019774
Kailang Yangc69aefa2010-08-17 10:39:22 +020019775 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
19776 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
19777 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
19778 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
19779 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
19780 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019781
19782 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19783 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19784 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19785 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19786 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yangc69aefa2010-08-17 10:39:22 +020019787
19788 {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
19789 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019790 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Kailang Yangc69aefa2010-08-17 10:39:22 +020019791
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019792 { }
19793};
19794
Kailang Yangc69aefa2010-08-17 10:39:22 +020019795/* toggle speaker-output according to the hp-jack state */
19796static void alc680_base_setup(struct hda_codec *codec)
19797{
19798 struct alc_spec *spec = codec->spec;
19799
19800 spec->autocfg.hp_pins[0] = 0x16;
19801 spec->autocfg.speaker_pins[0] = 0x14;
19802 spec->autocfg.speaker_pins[1] = 0x15;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019803 spec->autocfg.num_inputs = 2;
19804 spec->autocfg.inputs[0].pin = 0x18;
19805 spec->autocfg.inputs[0].type = AUTO_PIN_MIC;
19806 spec->autocfg.inputs[1].pin = 0x19;
Takashi Iwai86e29592010-09-09 14:50:17 +020019807 spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019808}
19809
19810static void alc680_unsol_event(struct hda_codec *codec,
19811 unsigned int res)
19812{
19813 if ((res >> 26) == ALC880_HP_EVENT)
19814 alc_automute_amp(codec);
19815 if ((res >> 26) == ALC880_MIC_EVENT)
19816 alc680_rec_autoswitch(codec);
19817}
19818
19819static void alc680_inithook(struct hda_codec *codec)
19820{
19821 alc_automute_amp(codec);
19822 alc680_rec_autoswitch(codec);
19823}
19824
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019825/* create input playback/capture controls for the given pin */
19826static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
19827 const char *ctlname, int idx)
19828{
19829 hda_nid_t dac;
19830 int err;
19831
19832 switch (nid) {
19833 case 0x14:
19834 dac = 0x02;
19835 break;
19836 case 0x15:
19837 dac = 0x03;
19838 break;
19839 case 0x16:
19840 dac = 0x04;
19841 break;
19842 default:
19843 return 0;
19844 }
19845 if (spec->multiout.dac_nids[0] != dac &&
19846 spec->multiout.dac_nids[1] != dac) {
19847 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
19848 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
19849 HDA_OUTPUT));
19850 if (err < 0)
19851 return err;
19852
19853 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
19854 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
19855
19856 if (err < 0)
19857 return err;
19858 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
19859 }
19860
19861 return 0;
19862}
19863
19864/* add playback controls from the parsed DAC table */
19865static int alc680_auto_create_multi_out_ctls(struct alc_spec *spec,
19866 const struct auto_pin_cfg *cfg)
19867{
19868 hda_nid_t nid;
19869 int err;
19870
19871 spec->multiout.dac_nids = spec->private_dac_nids;
19872
19873 nid = cfg->line_out_pins[0];
19874 if (nid) {
19875 const char *name;
19876 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
19877 name = "Speaker";
19878 else
19879 name = "Front";
19880 err = alc680_new_analog_output(spec, nid, name, 0);
19881 if (err < 0)
19882 return err;
19883 }
19884
19885 nid = cfg->speaker_pins[0];
19886 if (nid) {
19887 err = alc680_new_analog_output(spec, nid, "Speaker", 0);
19888 if (err < 0)
19889 return err;
19890 }
19891 nid = cfg->hp_pins[0];
19892 if (nid) {
19893 err = alc680_new_analog_output(spec, nid, "Headphone", 0);
19894 if (err < 0)
19895 return err;
19896 }
19897
19898 return 0;
19899}
19900
19901static void alc680_auto_set_output_and_unmute(struct hda_codec *codec,
19902 hda_nid_t nid, int pin_type)
19903{
19904 alc_set_pin_output(codec, nid, pin_type);
19905}
19906
19907static void alc680_auto_init_multi_out(struct hda_codec *codec)
19908{
19909 struct alc_spec *spec = codec->spec;
19910 hda_nid_t nid = spec->autocfg.line_out_pins[0];
19911 if (nid) {
19912 int pin_type = get_pin_type(spec->autocfg.line_out_type);
19913 alc680_auto_set_output_and_unmute(codec, nid, pin_type);
19914 }
19915}
19916
19917static void alc680_auto_init_hp_out(struct hda_codec *codec)
19918{
19919 struct alc_spec *spec = codec->spec;
19920 hda_nid_t pin;
19921
19922 pin = spec->autocfg.hp_pins[0];
19923 if (pin)
19924 alc680_auto_set_output_and_unmute(codec, pin, PIN_HP);
19925 pin = spec->autocfg.speaker_pins[0];
19926 if (pin)
19927 alc680_auto_set_output_and_unmute(codec, pin, PIN_OUT);
19928}
19929
19930/* pcm configuration: identical with ALC880 */
19931#define alc680_pcm_analog_playback alc880_pcm_analog_playback
19932#define alc680_pcm_analog_capture alc880_pcm_analog_capture
19933#define alc680_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
19934#define alc680_pcm_digital_playback alc880_pcm_digital_playback
Kailang Yangc69aefa2010-08-17 10:39:22 +020019935#define alc680_pcm_digital_capture alc880_pcm_digital_capture
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019936
19937/*
19938 * BIOS auto configuration
19939 */
19940static int alc680_parse_auto_config(struct hda_codec *codec)
19941{
19942 struct alc_spec *spec = codec->spec;
19943 int err;
19944 static hda_nid_t alc680_ignore[] = { 0 };
19945
19946 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
19947 alc680_ignore);
19948 if (err < 0)
19949 return err;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019950
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019951 if (!spec->autocfg.line_outs) {
19952 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
19953 spec->multiout.max_channels = 2;
19954 spec->no_analog = 1;
19955 goto dig_only;
19956 }
19957 return 0; /* can't find valid BIOS pin config */
19958 }
19959 err = alc680_auto_create_multi_out_ctls(spec, &spec->autocfg);
19960 if (err < 0)
19961 return err;
19962
19963 spec->multiout.max_channels = 2;
19964
19965 dig_only:
19966 /* digital only support output */
Takashi Iwai757899a2010-07-30 10:48:14 +020019967 alc_auto_parse_digital(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019968 if (spec->kctls.list)
19969 add_mixer(spec, spec->kctls.list);
19970
19971 add_verb(spec, alc680_init_verbs);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019972
19973 err = alc_auto_add_mic_boost(codec);
19974 if (err < 0)
19975 return err;
19976
19977 return 1;
19978}
19979
19980#define alc680_auto_init_analog_input alc882_auto_init_analog_input
19981
19982/* init callback for auto-configuration model -- overriding the default init */
19983static void alc680_auto_init(struct hda_codec *codec)
19984{
19985 struct alc_spec *spec = codec->spec;
19986 alc680_auto_init_multi_out(codec);
19987 alc680_auto_init_hp_out(codec);
19988 alc680_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020019989 alc_auto_init_digital(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019990 if (spec->unsol_event)
19991 alc_inithook(codec);
19992}
19993
19994/*
19995 * configuration and preset
19996 */
Takashi Iwaiea734962011-01-17 11:29:34 +010019997static const char * const alc680_models[ALC680_MODEL_LAST] = {
Takashi Iwaid4a86d82010-06-23 17:51:26 +020019998 [ALC680_BASE] = "base",
19999 [ALC680_AUTO] = "auto",
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020000};
20001
20002static struct snd_pci_quirk alc680_cfg_tbl[] = {
20003 SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE),
20004 {}
20005};
20006
20007static struct alc_config_preset alc680_presets[] = {
20008 [ALC680_BASE] = {
20009 .mixers = { alc680_base_mixer },
Kailang Yangc69aefa2010-08-17 10:39:22 +020020010 .cap_mixer = alc680_master_capture_mixer,
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020011 .init_verbs = { alc680_init_verbs },
20012 .num_dacs = ARRAY_SIZE(alc680_dac_nids),
20013 .dac_nids = alc680_dac_nids,
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020014 .dig_out_nid = ALC680_DIGOUT_NID,
20015 .num_channel_mode = ARRAY_SIZE(alc680_modes),
20016 .channel_mode = alc680_modes,
Kailang Yangc69aefa2010-08-17 10:39:22 +020020017 .unsol_event = alc680_unsol_event,
20018 .setup = alc680_base_setup,
20019 .init_hook = alc680_inithook,
20020
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020021 },
20022};
20023
20024static int patch_alc680(struct hda_codec *codec)
20025{
20026 struct alc_spec *spec;
20027 int board_config;
20028 int err;
20029
20030 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
20031 if (spec == NULL)
20032 return -ENOMEM;
20033
20034 codec->spec = spec;
20035
20036 board_config = snd_hda_check_board_config(codec, ALC680_MODEL_LAST,
20037 alc680_models,
20038 alc680_cfg_tbl);
20039
20040 if (board_config < 0 || board_config >= ALC680_MODEL_LAST) {
20041 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
20042 codec->chip_name);
20043 board_config = ALC680_AUTO;
20044 }
20045
20046 if (board_config == ALC680_AUTO) {
20047 /* automatic parse from the BIOS config */
20048 err = alc680_parse_auto_config(codec);
20049 if (err < 0) {
20050 alc_free(codec);
20051 return err;
20052 } else if (!err) {
20053 printk(KERN_INFO
20054 "hda_codec: Cannot set up configuration "
20055 "from BIOS. Using base mode...\n");
20056 board_config = ALC680_BASE;
20057 }
20058 }
20059
20060 if (board_config != ALC680_AUTO)
20061 setup_preset(codec, &alc680_presets[board_config]);
20062
20063 spec->stream_analog_playback = &alc680_pcm_analog_playback;
Kailang Yangc69aefa2010-08-17 10:39:22 +020020064 spec->stream_analog_capture = &alc680_pcm_analog_auto_capture;
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020065 spec->stream_digital_playback = &alc680_pcm_digital_playback;
Kailang Yangc69aefa2010-08-17 10:39:22 +020020066 spec->stream_digital_capture = &alc680_pcm_digital_capture;
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020067
20068 if (!spec->adc_nids) {
20069 spec->adc_nids = alc680_adc_nids;
20070 spec->num_adc_nids = ARRAY_SIZE(alc680_adc_nids);
20071 }
20072
20073 if (!spec->cap_mixer)
20074 set_capture_mixer(codec);
20075
20076 spec->vmaster_nid = 0x02;
20077
20078 codec->patch_ops = alc_patch_ops;
20079 if (board_config == ALC680_AUTO)
20080 spec->init_hook = alc680_auto_init;
20081
20082 return 0;
20083}
20084
20085/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070020086 * patch entries
20087 */
Takashi Iwai1289e9e2008-11-27 15:47:11 +010020088static struct hda_codec_preset snd_hda_preset_realtek[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070020089 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010020090 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010020091 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020020092 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010020093 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010020094 { .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +020020095 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010020096 { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010020097 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020020098 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010020099 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
20100 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
20101 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020020102 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
Takashi Iwai49535502009-06-30 15:28:30 +020020103 .patch = patch_alc882 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020020104 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
20105 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020020106 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Kailang Yangcec27c82010-02-04 14:18:18 +010020107 { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
Kailang Yang6227cdc2010-02-25 08:36:52 +010020108 { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020109 { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010020110 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070020111 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai49535502009-06-30 15:28:30 +020020112 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
Clive Messer669faba2008-09-30 15:49:13 +020020113 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
Takashi Iwai49535502009-06-30 15:28:30 +020020114 .patch = patch_alc882 },
Takashi Iwaicb308f92008-04-16 14:13:29 +020020115 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai49535502009-06-30 15:28:30 +020020116 .patch = patch_alc882 },
Kailang Yangdf694da2005-12-05 19:42:22 +010020117 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Kailang Yang01e0f132010-11-22 10:59:36 +010020118 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc888 },
Kailang Yang44426082008-10-15 11:18:05 +020020119 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
Takashi Iwai49535502009-06-30 15:28:30 +020020120 .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010020121 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },
Takashi Iwai49535502009-06-30 15:28:30 +020020122 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010020123 { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070020124 {} /* terminator */
20125};
Takashi Iwai1289e9e2008-11-27 15:47:11 +010020126
20127MODULE_ALIAS("snd-hda-codec-id:10ec*");
20128
20129MODULE_LICENSE("GPL");
20130MODULE_DESCRIPTION("Realtek HD-audio codec");
20131
20132static struct hda_codec_preset_list realtek_list = {
20133 .preset = snd_hda_preset_realtek,
20134 .owner = THIS_MODULE,
20135};
20136
20137static int __init patch_realtek_init(void)
20138{
20139 return snd_hda_add_codec_preset(&realtek_list);
20140}
20141
20142static void __exit patch_realtek_exit(void)
20143{
20144 snd_hda_delete_codec_preset(&realtek_list);
20145}
20146
20147module_init(patch_realtek_init)
20148module_exit(patch_realtek_exit)