blob: a0f27b999928b93197a7a16e7589b0a7b3b4dbd1 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for ALC 260/880/882 codecs
5 *
Kailang Yangdf694da2005-12-05 19:42:22 +01006 * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
7 * PeiSen Hou <pshou@realtek.com.tw>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * Takashi Iwai <tiwai@suse.de>
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01009 * Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * This driver is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This driver is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/init.h>
27#include <linux/delay.h>
28#include <linux/slab.h>
29#include <linux/pci.h>
30#include <sound/core.h>
Kailang Yang9ad0e492010-09-14 23:22:00 +020031#include <sound/jack.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include "hda_codec.h"
33#include "hda_local.h"
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090034#include "hda_beep.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
Kailang Yangccc656c2006-10-17 12:32:26 +020036#define ALC880_FRONT_EVENT 0x01
37#define ALC880_DCVOL_EVENT 0x02
38#define ALC880_HP_EVENT 0x04
39#define ALC880_MIC_EVENT 0x08
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
41/* ALC880 board config type */
42enum {
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 ALC880_3ST,
44 ALC880_3ST_DIG,
45 ALC880_5ST,
46 ALC880_5ST_DIG,
47 ALC880_W810,
Takashi Iwaidfc0ff62005-05-12 14:31:49 +020048 ALC880_Z71V,
Takashi Iwaib6482d42005-06-27 15:32:43 +020049 ALC880_6ST,
Takashi Iwai16ded522005-06-10 19:58:24 +020050 ALC880_6ST_DIG,
51 ALC880_F1734,
52 ALC880_ASUS,
53 ALC880_ASUS_DIG,
54 ALC880_ASUS_W1V,
Kailang Yangdf694da2005-12-05 19:42:22 +010055 ALC880_ASUS_DIG2,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +010056 ALC880_FUJITSU,
Takashi Iwai16ded522005-06-10 19:58:24 +020057 ALC880_UNIWILL_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +020058 ALC880_UNIWILL,
59 ALC880_UNIWILL_P53,
Kailang Yangdf694da2005-12-05 19:42:22 +010060 ALC880_CLEVO,
61 ALC880_TCL_S700,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010062 ALC880_LG,
Takashi Iwaid6815182006-03-23 16:06:23 +010063 ALC880_LG_LW,
Takashi Iwaidf99cd32008-04-25 15:25:04 +020064 ALC880_MEDION_RIM,
Takashi Iwaie9edcee2005-06-13 14:16:38 +020065#ifdef CONFIG_SND_DEBUG
66 ALC880_TEST,
67#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010068 ALC880_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020069 ALC880_MODEL_LAST /* last tag */
70};
71
72/* ALC260 models */
73enum {
74 ALC260_BASIC,
75 ALC260_HP,
Kailang Yang3f878302008-08-26 13:02:23 +020076 ALC260_HP_DC7600,
Kailang Yangdf694da2005-12-05 19:42:22 +010077 ALC260_HP_3013,
78 ALC260_FUJITSU_S702X,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +010079 ALC260_ACER,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020080 ALC260_WILL,
81 ALC260_REPLACER_672V,
Michael Schwingencc959482009-02-22 18:58:45 +010082 ALC260_FAVORIT100,
Jonathan Woithe7cf51e482006-02-09 12:01:26 +010083#ifdef CONFIG_SND_DEBUG
84 ALC260_TEST,
85#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010086 ALC260_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020087 ALC260_MODEL_LAST /* last tag */
Linus Torvalds1da177e2005-04-16 15:20:36 -070088};
89
Kailang Yangdf694da2005-12-05 19:42:22 +010090/* ALC262 models */
91enum {
92 ALC262_BASIC,
Kailang Yangccc656c2006-10-17 12:32:26 +020093 ALC262_HIPPO,
94 ALC262_HIPPO_1,
Takashi Iwai834be882006-03-01 14:16:17 +010095 ALC262_FUJITSU,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020096 ALC262_HP_BPC,
Kailang Yangcd7509a2007-01-26 18:33:17 +010097 ALC262_HP_BPC_D7000_WL,
98 ALC262_HP_BPC_D7000_WF,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010099 ALC262_HP_TC_T5735,
Kailang Yang8c427222008-01-10 13:03:59 +0100100 ALC262_HP_RP5700,
Takashi Iwai304dcaa2006-07-25 14:51:16 +0200101 ALC262_BENQ_ED8,
Kailang Yang272a5272007-05-14 11:00:38 +0200102 ALC262_SONY_ASSAMD,
Kailang Yang83c34212007-07-05 11:43:05 +0200103 ALC262_BENQ_T31,
Tobin Davisf651b502007-10-26 12:40:47 +0200104 ALC262_ULTRA,
Jiang zhe0e31daf2008-03-20 12:12:39 +0100105 ALC262_LENOVO_3000,
Pascal Terjane8f9ae22008-08-04 14:36:05 +0200106 ALC262_NEC,
Kailang Yang4e555fe2008-08-26 13:05:55 +0200107 ALC262_TOSHIBA_S06,
Hiroshi Miura9f99a632008-08-28 16:09:06 +0200108 ALC262_TOSHIBA_RX1,
Tony Vroonba340e82009-02-02 19:01:30 +0000109 ALC262_TYAN,
Kailang Yangdf694da2005-12-05 19:42:22 +0100110 ALC262_AUTO,
111 ALC262_MODEL_LAST /* last tag */
112};
113
Kailang Yanga361d842007-06-05 12:30:55 +0200114/* ALC268 models */
115enum {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +0200116 ALC267_QUANTA_IL1,
Kailang Yanga361d842007-06-05 12:30:55 +0200117 ALC268_3ST,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200118 ALC268_TOSHIBA,
Takashi Iwaid2738092007-08-16 14:59:45 +0200119 ALC268_ACER,
Takashi Iwaic238b4f2008-11-05 14:57:20 +0100120 ALC268_ACER_DMIC,
Kailang Yang8ef355d2008-08-26 13:10:22 +0200121 ALC268_ACER_ASPIRE_ONE,
Takashi Iwai3866f0b2008-01-15 12:37:42 +0100122 ALC268_DELL,
Mirco Tischlerf12462c2008-02-04 12:33:59 +0100123 ALC268_ZEPTO,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +0100124#ifdef CONFIG_SND_DEBUG
125 ALC268_TEST,
126#endif
Kailang Yanga361d842007-06-05 12:30:55 +0200127 ALC268_AUTO,
128 ALC268_MODEL_LAST /* last tag */
129};
130
Kailang Yangf6a92242007-12-13 16:52:54 +0100131/* ALC269 models */
132enum {
133 ALC269_BASIC,
Kailang Yang60db6b52008-08-26 13:13:00 +0200134 ALC269_QUANTA_FL1,
Kailang Yang84898e82010-02-04 14:16:14 +0100135 ALC269_AMIC,
136 ALC269_DMIC,
137 ALC269VB_AMIC,
138 ALC269VB_DMIC,
Takashi Iwai26f5df22008-11-03 17:39:46 +0100139 ALC269_FUJITSU,
Tony Vroon64154832008-11-06 15:08:49 +0000140 ALC269_LIFEBOOK,
Kailang Yangfe3eb0a2010-08-06 10:02:57 +0200141 ALC271_ACER,
Kailang Yangf6a92242007-12-13 16:52:54 +0100142 ALC269_AUTO,
143 ALC269_MODEL_LAST /* last tag */
144};
145
Kailang Yangdf694da2005-12-05 19:42:22 +0100146/* ALC861 models */
147enum {
148 ALC861_3ST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200149 ALC660_3ST,
Kailang Yangdf694da2005-12-05 19:42:22 +0100150 ALC861_3ST_DIG,
151 ALC861_6ST_DIG,
Takashi Iwai22309c32006-08-09 16:57:28 +0200152 ALC861_UNIWILL_M31,
Tobin Davisa53d1ae2006-10-17 12:00:28 +0200153 ALC861_TOSHIBA,
Mariusz Domanski7cdbff92006-10-23 13:42:56 +0200154 ALC861_ASUS,
Takashi Iwai56bb0ca2006-11-22 11:52:52 +0100155 ALC861_ASUS_LAPTOP,
Kailang Yangdf694da2005-12-05 19:42:22 +0100156 ALC861_AUTO,
157 ALC861_MODEL_LAST,
158};
159
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100160/* ALC861-VD models */
161enum {
162 ALC660VD_3ST,
Mike Crash6963f842007-06-25 12:12:51 +0200163 ALC660VD_3ST_DIG,
Takashi Iwai13c94742008-11-05 08:06:08 +0100164 ALC660VD_ASUS_V1S,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100165 ALC861VD_3ST,
166 ALC861VD_3ST_DIG,
167 ALC861VD_6ST_DIG,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200168 ALC861VD_LENOVO,
Kailang Yang272a5272007-05-14 11:00:38 +0200169 ALC861VD_DALLAS,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200170 ALC861VD_HP,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100171 ALC861VD_AUTO,
172 ALC861VD_MODEL_LAST,
173};
174
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200175/* ALC662 models */
176enum {
177 ALC662_3ST_2ch_DIG,
178 ALC662_3ST_6ch_DIG,
179 ALC662_3ST_6ch,
180 ALC662_5ST_DIG,
181 ALC662_LENOVO_101E,
Kailang Yang291702f2007-10-16 14:28:03 +0200182 ALC662_ASUS_EEEPC_P701,
Kailang Yang8c427222008-01-10 13:03:59 +0100183 ALC662_ASUS_EEEPC_EP20,
Kailang Yang6dda9f42008-05-27 12:05:31 +0200184 ALC663_ASUS_M51VA,
185 ALC663_ASUS_G71V,
186 ALC663_ASUS_H13,
187 ALC663_ASUS_G50V,
Kailang Yangf1d4e282008-08-26 14:03:29 +0200188 ALC662_ECS,
189 ALC663_ASUS_MODE1,
190 ALC662_ASUS_MODE2,
191 ALC663_ASUS_MODE3,
192 ALC663_ASUS_MODE4,
193 ALC663_ASUS_MODE5,
194 ALC663_ASUS_MODE6,
Kailang Yangebb83ee2009-12-17 12:23:00 +0100195 ALC663_ASUS_MODE7,
196 ALC663_ASUS_MODE8,
Kailang Yang622e84c2009-04-21 07:39:04 +0200197 ALC272_DELL,
198 ALC272_DELL_ZM1,
Chris Pockelé9541ba12009-05-12 08:08:53 +0200199 ALC272_SAMSUNG_NC10,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200200 ALC662_AUTO,
201 ALC662_MODEL_LAST,
202};
203
Kailang Yangdf694da2005-12-05 19:42:22 +0100204/* ALC882 models */
205enum {
206 ALC882_3ST_DIG,
207 ALC882_6ST_DIG,
Takashi Iwai4b146cb2006-07-28 14:42:36 +0200208 ALC882_ARIMA,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200209 ALC882_W2JC,
Kailang Yang272a5272007-05-14 11:00:38 +0200210 ALC882_TARGA,
211 ALC882_ASUS_A7J,
Takashi Iwai914759b2007-09-06 14:52:04 +0200212 ALC882_ASUS_A7M,
Tobin Davis9102cd12006-12-15 10:02:12 +0100213 ALC885_MACPRO,
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -0800214 ALC885_MBA21,
Takashi Iwai87350ad2007-08-16 18:19:38 +0200215 ALC885_MBP3,
Kacper Szczesniak41d55452009-05-07 12:47:43 +0200216 ALC885_MB5,
Luke Yelaviche458b1f2010-02-12 16:28:29 +1100217 ALC885_MACMINI3,
Nicola Fagnanic54728d2007-07-19 23:28:52 +0200218 ALC885_IMAC24,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -0800219 ALC885_IMAC91,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200220 ALC883_3ST_2ch_DIG,
221 ALC883_3ST_6ch_DIG,
222 ALC883_3ST_6ch,
223 ALC883_6ST_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +0200224 ALC883_TARGA_DIG,
225 ALC883_TARGA_2ch_DIG,
David Heidelberger64a8be72009-06-08 16:15:18 +0200226 ALC883_TARGA_8ch_DIG,
Vladimir Avdoninbab282b92006-08-22 13:31:58 +0200227 ALC883_ACER,
Tobin Davis2880a862007-08-07 11:50:26 +0200228 ALC883_ACER_ASPIRE,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +0800229 ALC888_ACER_ASPIRE_4930G,
Tony Vroond2fd4b02009-06-21 00:40:10 +0100230 ALC888_ACER_ASPIRE_6530G,
Hector Martin3b315d72009-06-02 10:54:19 +0200231 ALC888_ACER_ASPIRE_8930G,
Denis Kuplyakovfc86f952009-08-25 18:15:59 +0200232 ALC888_ACER_ASPIRE_7730G,
Tobin Davisc07584c2006-10-13 12:32:16 +0200233 ALC883_MEDION,
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ünther3e1647c52009-06-05 00:47:26 +0200255 ALC883_SONY_VAIO_TT,
Takashi Iwai4953550a2009-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 Iwai4953550a2009-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 Woithe7cf51e482006-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 Woithe7cf51e482006-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 Woithe7cf51e482006-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 Kluin4b35d2ca2009-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
Łukasz Wojniłowicz460c92f2011-02-07 13:13:27 +01002293static struct snd_kcontrol_new alc888_acer_aspire_4930g_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),
Łukasz Wojniłowicz786c51f2011-02-24 10:03:31 +01002298 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
Łukasz Wojniłowicz460c92f2011-02-07 13:13:27 +01002299 HDA_OUTPUT),
Łukasz Wojniłowicz786c51f2011-02-24 10:03:31 +01002300 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2301 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2302 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2303 HDA_CODEC_VOLUME_MONO("Internal LFE Playback Volume", 0x0f, 1, 0x0, HDA_OUTPUT),
2304 HDA_BIND_MUTE_MONO("Internal LFE Playback Switch", 0x0f, 1, 2, HDA_INPUT),
Łukasz Wojniłowicz460c92f2011-02-07 13:13:27 +01002305 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2306 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2307 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2308 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2309 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2310 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
2311 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2312 { } /* end */
2313};
2314
Hector Martin556eea92009-12-20 22:51:23 +01002315static struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = {
2316 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2317 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2318 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2319 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2320 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
2321 HDA_OUTPUT),
2322 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2323 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2324 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2325 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2326 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2327 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01002328 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Hector Martin556eea92009-12-20 22:51:23 +01002329 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2330 { } /* end */
2331};
2332
2333
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002334static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec)
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002335{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002336 struct alc_spec *spec = codec->spec;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002337
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002338 spec->autocfg.hp_pins[0] = 0x15;
2339 spec->autocfg.speaker_pins[0] = 0x14;
Łukasz Wojniłowicz7cef4cf2009-11-20 12:14:35 +01002340 spec->autocfg.speaker_pins[1] = 0x16;
2341 spec->autocfg.speaker_pins[2] = 0x17;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002342}
2343
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002344static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec)
Emilio López320d5922009-06-25 08:18:44 +02002345{
2346 struct alc_spec *spec = codec->spec;
2347
2348 spec->autocfg.hp_pins[0] = 0x15;
2349 spec->autocfg.speaker_pins[0] = 0x14;
2350 spec->autocfg.speaker_pins[1] = 0x16;
2351 spec->autocfg.speaker_pins[2] = 0x17;
Emilio López320d5922009-06-25 08:18:44 +02002352}
2353
Denis Kuplyakovd9477202010-11-24 06:01:09 +01002354static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec)
2355{
2356 struct alc_spec *spec = codec->spec;
2357
2358 spec->autocfg.hp_pins[0] = 0x15;
2359 spec->autocfg.speaker_pins[0] = 0x14;
2360 spec->autocfg.speaker_pins[1] = 0x16;
2361 spec->autocfg.speaker_pins[2] = 0x17;
2362}
2363
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002364static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
Hector Martin3b315d72009-06-02 10:54:19 +02002365{
2366 struct alc_spec *spec = codec->spec;
2367
2368 spec->autocfg.hp_pins[0] = 0x15;
2369 spec->autocfg.speaker_pins[0] = 0x14;
2370 spec->autocfg.speaker_pins[1] = 0x16;
2371 spec->autocfg.speaker_pins[2] = 0x1b;
Hector Martin3b315d72009-06-02 10:54:19 +02002372}
2373
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002374/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002375 * ALC880 3-stack model
2376 *
2377 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002378 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
2379 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 */
2381
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002382static hda_nid_t alc880_dac_nids[4] = {
2383 /* front, rear, clfe, rear_surr */
2384 0x02, 0x05, 0x04, 0x03
2385};
2386
2387static hda_nid_t alc880_adc_nids[3] = {
2388 /* ADC0-2 */
2389 0x07, 0x08, 0x09,
2390};
2391
2392/* The datasheet says the node 0x07 is connected from inputs,
2393 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +01002394 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002396static hda_nid_t alc880_adc_nids_alt[2] = {
2397 /* ADC1-2 */
2398 0x08, 0x09,
2399};
2400
2401#define ALC880_DIGOUT_NID 0x06
2402#define ALC880_DIGIN_NID 0x0a
2403
2404static struct hda_input_mux alc880_capture_source = {
2405 .num_items = 4,
2406 .items = {
2407 { "Mic", 0x0 },
2408 { "Front Mic", 0x3 },
2409 { "Line", 0x2 },
2410 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002412};
2413
2414/* channel source setting (2/6 channel selection for 3-stack) */
2415/* 2ch mode */
2416static struct hda_verb alc880_threestack_ch2_init[] = {
2417 /* set line-in to input, mute it */
2418 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2419 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2420 /* set mic-in to input vref 80%, mute it */
2421 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2422 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 { } /* end */
2424};
2425
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002426/* 6ch mode */
2427static struct hda_verb alc880_threestack_ch6_init[] = {
2428 /* set line-in to output, unmute it */
2429 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2430 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2431 /* set mic-in to output, unmute it */
2432 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2433 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2434 { } /* end */
2435};
2436
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002437static struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002438 { 2, alc880_threestack_ch2_init },
2439 { 6, alc880_threestack_ch6_init },
2440};
2441
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002442static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002443 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002444 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02002445 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002446 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02002447 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2448 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002449 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2450 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2452 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2453 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2454 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2455 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2456 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2457 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
2458 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002460 {
2461 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2462 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002463 .info = alc_ch_mode_info,
2464 .get = alc_ch_mode_get,
2465 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002466 },
2467 { } /* end */
2468};
2469
2470/* capture mixer elements */
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002471static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
2472 struct snd_ctl_elem_info *uinfo)
2473{
2474 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2475 struct alc_spec *spec = codec->spec;
2476 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002477
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002478 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002479 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
2480 HDA_INPUT);
2481 err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002482 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002483 return err;
2484}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002486static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
2487 unsigned int size, unsigned int __user *tlv)
2488{
2489 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2490 struct alc_spec *spec = codec->spec;
2491 int err;
2492
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002493 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002494 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
2495 HDA_INPUT);
2496 err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002497 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002498 return err;
2499}
2500
2501typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
2502 struct snd_ctl_elem_value *ucontrol);
2503
2504static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
2505 struct snd_ctl_elem_value *ucontrol,
2506 getput_call_t func)
2507{
2508 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2509 struct alc_spec *spec = codec->spec;
2510 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
2511 int err;
2512
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002513 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002514 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[adc_idx],
2515 3, 0, HDA_INPUT);
2516 err = func(kcontrol, ucontrol);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002517 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002518 return err;
2519}
2520
2521static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
2522 struct snd_ctl_elem_value *ucontrol)
2523{
2524 return alc_cap_getput_caller(kcontrol, ucontrol,
2525 snd_hda_mixer_amp_volume_get);
2526}
2527
2528static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
2529 struct snd_ctl_elem_value *ucontrol)
2530{
2531 return alc_cap_getput_caller(kcontrol, ucontrol,
2532 snd_hda_mixer_amp_volume_put);
2533}
2534
2535/* capture mixer elements */
2536#define alc_cap_sw_info snd_ctl_boolean_stereo_info
2537
2538static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
2539 struct snd_ctl_elem_value *ucontrol)
2540{
2541 return alc_cap_getput_caller(kcontrol, ucontrol,
2542 snd_hda_mixer_amp_switch_get);
2543}
2544
2545static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
2546 struct snd_ctl_elem_value *ucontrol)
2547{
2548 return alc_cap_getput_caller(kcontrol, ucontrol,
2549 snd_hda_mixer_amp_switch_put);
2550}
2551
Takashi Iwaia23b6882009-03-23 15:21:36 +01002552#define _DEFINE_CAPMIX(num) \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002553 { \
2554 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2555 .name = "Capture Switch", \
2556 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
2557 .count = num, \
2558 .info = alc_cap_sw_info, \
2559 .get = alc_cap_sw_get, \
2560 .put = alc_cap_sw_put, \
2561 }, \
2562 { \
2563 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2564 .name = "Capture Volume", \
2565 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
2566 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
2567 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
2568 .count = num, \
2569 .info = alc_cap_vol_info, \
2570 .get = alc_cap_vol_get, \
2571 .put = alc_cap_vol_put, \
2572 .tlv = { .c = alc_cap_vol_tlv }, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002573 }
2574
2575#define _DEFINE_CAPSRC(num) \
Takashi Iwai3c3e9892008-10-31 17:48:56 +01002576 { \
2577 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2578 /* .name = "Capture Source", */ \
2579 .name = "Input Source", \
2580 .count = num, \
2581 .info = alc_mux_enum_info, \
2582 .get = alc_mux_enum_get, \
2583 .put = alc_mux_enum_put, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002584 }
2585
2586#define DEFINE_CAPMIX(num) \
2587static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
2588 _DEFINE_CAPMIX(num), \
2589 _DEFINE_CAPSRC(num), \
2590 { } /* end */ \
2591}
2592
2593#define DEFINE_CAPMIX_NOSRC(num) \
2594static struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
2595 _DEFINE_CAPMIX(num), \
2596 { } /* end */ \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002597}
2598
2599/* up to three ADCs */
2600DEFINE_CAPMIX(1);
2601DEFINE_CAPMIX(2);
2602DEFINE_CAPMIX(3);
Takashi Iwaia23b6882009-03-23 15:21:36 +01002603DEFINE_CAPMIX_NOSRC(1);
2604DEFINE_CAPMIX_NOSRC(2);
2605DEFINE_CAPMIX_NOSRC(3);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002606
2607/*
2608 * ALC880 5-stack model
2609 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002610 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
2611 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002612 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
2613 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
2614 */
2615
2616/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002617static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002618 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002619 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 { } /* end */
2621};
2622
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002623/* channel source setting (6/8 channel selection for 5-stack) */
2624/* 6ch mode */
2625static struct hda_verb alc880_fivestack_ch6_init[] = {
2626 /* set line-in to input, mute it */
2627 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2628 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002629 { } /* end */
2630};
2631
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002632/* 8ch mode */
2633static struct hda_verb alc880_fivestack_ch8_init[] = {
2634 /* set line-in to output, unmute it */
2635 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2636 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2637 { } /* end */
2638};
2639
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002640static struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002641 { 6, alc880_fivestack_ch6_init },
2642 { 8, alc880_fivestack_ch8_init },
2643};
2644
2645
2646/*
2647 * ALC880 6-stack model
2648 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002649 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
2650 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002651 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
2652 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
2653 */
2654
2655static hda_nid_t alc880_6st_dac_nids[4] = {
2656 /* front, rear, clfe, rear_surr */
2657 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002658};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002659
2660static struct hda_input_mux alc880_6stack_capture_source = {
2661 .num_items = 4,
2662 .items = {
2663 { "Mic", 0x0 },
2664 { "Front Mic", 0x1 },
2665 { "Line", 0x2 },
2666 { "CD", 0x4 },
2667 },
2668};
2669
2670/* fixed 8-channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002671static struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002672 { 8, NULL },
2673};
2674
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002675static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002676 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002677 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002678 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002679 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002680 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2681 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002682 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2683 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002684 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002685 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002686 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2687 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2688 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2689 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2690 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2691 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2692 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2693 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002694 {
2695 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2696 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002697 .info = alc_ch_mode_info,
2698 .get = alc_ch_mode_get,
2699 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02002700 },
2701 { } /* end */
2702};
2703
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002704
2705/*
2706 * ALC880 W810 model
2707 *
2708 * W810 has rear IO for:
2709 * Front (DAC 02)
2710 * Surround (DAC 03)
2711 * Center/LFE (DAC 04)
2712 * Digital out (06)
2713 *
2714 * The system also has a pair of internal speakers, and a headphone jack.
2715 * These are both connected to Line2 on the codec, hence to DAC 02.
Kailang Yangea1fb292008-08-26 12:58:38 +02002716 *
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002717 * There is a variable resistor to control the speaker or headphone
2718 * volume. This is a hardware-only device without a software API.
2719 *
2720 * Plugging headphones in will disable the internal speakers. This is
2721 * implemented in hardware, not via the driver using jack sense. In
2722 * a similar fashion, plugging into the rear socket marked "front" will
2723 * disable both the speakers and headphones.
2724 *
2725 * For input, there's a microphone jack, and an "audio in" jack.
2726 * These may not do anything useful with this driver yet, because I
2727 * haven't setup any initialization verbs for these yet...
2728 */
2729
2730static hda_nid_t alc880_w810_dac_nids[3] = {
2731 /* front, rear/surround, clfe */
2732 0x02, 0x03, 0x04
2733};
2734
2735/* fixed 6 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002736static struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002737 { 6, NULL }
2738};
2739
2740/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002741static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002742 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002743 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002744 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002745 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002746 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2747 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002748 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2749 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002750 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
2751 { } /* end */
2752};
2753
2754
2755/*
2756 * Z710V model
2757 *
2758 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002759 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
2760 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002761 */
2762
2763static hda_nid_t alc880_z71v_dac_nids[1] = {
2764 0x02
2765};
2766#define ALC880_Z71V_HP_DAC 0x03
2767
2768/* fixed 2 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002769static struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002770 { 2, NULL }
2771};
2772
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002773static struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002774 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002775 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002776 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002777 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002778 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2779 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2780 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2781 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2782 { } /* end */
2783};
2784
2785
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002786/*
2787 * ALC880 F1734 model
2788 *
2789 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
2790 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
2791 */
2792
2793static hda_nid_t alc880_f1734_dac_nids[1] = {
2794 0x03
2795};
2796#define ALC880_F1734_HP_DAC 0x02
2797
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002798static struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002799 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002800 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01002801 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2802 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002803 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2804 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01002805 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2806 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002807 { } /* end */
2808};
2809
Takashi Iwai937b4162008-02-11 14:52:36 +01002810static struct hda_input_mux alc880_f1734_capture_source = {
2811 .num_items = 2,
2812 .items = {
2813 { "Mic", 0x1 },
2814 { "CD", 0x4 },
2815 },
2816};
2817
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002818
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002819/*
2820 * ALC880 ASUS model
2821 *
2822 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
2823 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
2824 * Mic = 0x18, Line = 0x1a
2825 */
2826
2827#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
2828#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
2829
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002830static struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002831 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002832 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002833 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002834 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002835 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2836 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002837 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2838 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002839 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2840 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2841 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2842 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2843 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2844 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002845 {
2846 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2847 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002848 .info = alc_ch_mode_info,
2849 .get = alc_ch_mode_get,
2850 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02002851 },
2852 { } /* end */
2853};
2854
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002855/*
2856 * ALC880 ASUS W1V model
2857 *
2858 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
2859 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
2860 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
2861 */
2862
2863/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002864static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002865 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
2866 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002867 { } /* end */
2868};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002869
Kailang Yangdf694da2005-12-05 19:42:22 +01002870/* TCL S700 */
2871static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
2872 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2873 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
2874 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
2875 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
2876 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
2877 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
2878 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
2879 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
2880 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01002881 { } /* end */
2882};
2883
Kailang Yangccc656c2006-10-17 12:32:26 +02002884/* Uniwill */
2885static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002886 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2887 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2888 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2889 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002890 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2891 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2892 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2893 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2894 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2895 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2896 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2897 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2898 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2899 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2900 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2901 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002902 {
2903 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2904 .name = "Channel Mode",
2905 .info = alc_ch_mode_info,
2906 .get = alc_ch_mode_get,
2907 .put = alc_ch_mode_put,
2908 },
2909 { } /* end */
2910};
2911
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002912static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
2913 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2914 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2915 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2916 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
2917 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2918 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
David Henningsson8607f7c2010-12-20 14:43:54 +01002919 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2920 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01002921 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2922 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002923 { } /* end */
2924};
2925
Kailang Yangccc656c2006-10-17 12:32:26 +02002926static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002927 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2928 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2929 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2930 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002931 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2932 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2933 { } /* end */
2934};
2935
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01002937 * virtual master controls
2938 */
2939
2940/*
2941 * slave controls for virtual master
2942 */
Takashi Iwaiea734962011-01-17 11:29:34 +01002943static const char * const alc_slave_vols[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002944 "Front Playback Volume",
2945 "Surround Playback Volume",
2946 "Center Playback Volume",
2947 "LFE Playback Volume",
2948 "Side Playback Volume",
2949 "Headphone Playback Volume",
2950 "Speaker Playback Volume",
2951 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002952 "Line-Out Playback Volume",
Takashi Iwai26f5df22008-11-03 17:39:46 +01002953 "PCM Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002954 NULL,
2955};
2956
Takashi Iwaiea734962011-01-17 11:29:34 +01002957static const char * const alc_slave_sws[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002958 "Front Playback Switch",
2959 "Surround Playback Switch",
2960 "Center Playback Switch",
2961 "LFE Playback Switch",
2962 "Side Playback Switch",
2963 "Headphone Playback Switch",
2964 "Speaker Playback Switch",
2965 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01002966 "IEC958 Playback Switch",
Takashi Iwai23033b22009-12-08 12:36:52 +01002967 "Line-Out Playback Switch",
2968 "PCM Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002969 NULL,
2970};
2971
2972/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002973 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 */
Takashi Iwai603c4012008-07-30 15:01:44 +02002975
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002976#define NID_MAPPING (-1)
2977
2978#define SUBDEV_SPEAKER_ (0 << 6)
2979#define SUBDEV_HP_ (1 << 6)
2980#define SUBDEV_LINE_ (2 << 6)
2981#define SUBDEV_SPEAKER(x) (SUBDEV_SPEAKER_ | ((x) & 0x3f))
2982#define SUBDEV_HP(x) (SUBDEV_HP_ | ((x) & 0x3f))
2983#define SUBDEV_LINE(x) (SUBDEV_LINE_ | ((x) & 0x3f))
2984
Takashi Iwai603c4012008-07-30 15:01:44 +02002985static void alc_free_kctls(struct hda_codec *codec);
2986
Takashi Iwai67d634c2009-11-16 15:35:59 +01002987#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002988/* additional beep mixers; the actual parameters are overwritten at build */
2989static struct snd_kcontrol_new alc_beep_mixer[] = {
2990 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
Jaroslav Kysela123c07a2009-10-21 14:48:23 +02002991 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002992 { } /* end */
2993};
Takashi Iwai67d634c2009-11-16 15:35:59 +01002994#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002995
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996static int alc_build_controls(struct hda_codec *codec)
2997{
2998 struct alc_spec *spec = codec->spec;
Takashi Iwai2f44f842010-06-22 11:12:32 +02002999 struct snd_kcontrol *kctl = NULL;
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003000 struct snd_kcontrol_new *knew;
3001 int i, j, err;
3002 unsigned int u;
3003 hda_nid_t nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004
3005 for (i = 0; i < spec->num_mixers; i++) {
3006 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
3007 if (err < 0)
3008 return err;
3009 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01003010 if (spec->cap_mixer) {
3011 err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
3012 if (err < 0)
3013 return err;
3014 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003016 err = snd_hda_create_spdif_out_ctls(codec,
3017 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 if (err < 0)
3019 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003020 if (!spec->no_analog) {
3021 err = snd_hda_create_spdif_share_sw(codec,
3022 &spec->multiout);
3023 if (err < 0)
3024 return err;
3025 spec->multiout.share_spdif = 1;
3026 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 }
3028 if (spec->dig_in_nid) {
3029 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
3030 if (err < 0)
3031 return err;
3032 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01003033
Takashi Iwai67d634c2009-11-16 15:35:59 +01003034#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003035 /* create beep controls if needed */
3036 if (spec->beep_amp) {
3037 struct snd_kcontrol_new *knew;
3038 for (knew = alc_beep_mixer; knew->name; knew++) {
3039 struct snd_kcontrol *kctl;
3040 kctl = snd_ctl_new1(knew, codec);
3041 if (!kctl)
3042 return -ENOMEM;
3043 kctl->private_value = spec->beep_amp;
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01003044 err = snd_hda_ctl_add(codec, 0, kctl);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003045 if (err < 0)
3046 return err;
3047 }
3048 }
Takashi Iwai67d634c2009-11-16 15:35:59 +01003049#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003050
Takashi Iwai2134ea42008-01-10 16:53:55 +01003051 /* if we have no master control, let's create it */
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003052 if (!spec->no_analog &&
3053 !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01003054 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01003055 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01003056 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01003057 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01003058 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01003059 if (err < 0)
3060 return err;
3061 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003062 if (!spec->no_analog &&
3063 !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003064 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
3065 NULL, alc_slave_sws);
3066 if (err < 0)
3067 return err;
3068 }
3069
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003070 /* assign Capture Source enums to NID */
Takashi Iwaifbe618f2010-06-11 11:24:58 +02003071 if (spec->capsrc_nids || spec->adc_nids) {
3072 kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
3073 if (!kctl)
3074 kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
3075 for (i = 0; kctl && i < kctl->count; i++) {
3076 hda_nid_t *nids = spec->capsrc_nids;
3077 if (!nids)
3078 nids = spec->adc_nids;
3079 err = snd_hda_add_nid(codec, kctl, i, nids[i]);
3080 if (err < 0)
3081 return err;
3082 }
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003083 }
3084 if (spec->cap_mixer) {
3085 const char *kname = kctl ? kctl->id.name : NULL;
3086 for (knew = spec->cap_mixer; knew->name; knew++) {
3087 if (kname && strcmp(knew->name, kname) == 0)
3088 continue;
3089 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
3090 for (i = 0; kctl && i < kctl->count; i++) {
3091 err = snd_hda_add_nid(codec, kctl, i,
3092 spec->adc_nids[i]);
3093 if (err < 0)
3094 return err;
3095 }
3096 }
3097 }
3098
3099 /* other nid->control mapping */
3100 for (i = 0; i < spec->num_mixers; i++) {
3101 for (knew = spec->mixers[i]; knew->name; knew++) {
3102 if (knew->iface != NID_MAPPING)
3103 continue;
3104 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
3105 if (kctl == NULL)
3106 continue;
3107 u = knew->subdevice;
3108 for (j = 0; j < 4; j++, u >>= 8) {
3109 nid = u & 0x3f;
3110 if (nid == 0)
3111 continue;
3112 switch (u & 0xc0) {
3113 case SUBDEV_SPEAKER_:
3114 nid = spec->autocfg.speaker_pins[nid];
3115 break;
3116 case SUBDEV_LINE_:
3117 nid = spec->autocfg.line_out_pins[nid];
3118 break;
3119 case SUBDEV_HP_:
3120 nid = spec->autocfg.hp_pins[nid];
3121 break;
3122 default:
3123 continue;
3124 }
3125 err = snd_hda_add_nid(codec, kctl, 0, nid);
3126 if (err < 0)
3127 return err;
3128 }
3129 u = knew->private_value;
3130 for (j = 0; j < 4; j++, u >>= 8) {
3131 nid = u & 0xff;
3132 if (nid == 0)
3133 continue;
3134 err = snd_hda_add_nid(codec, kctl, 0, nid);
3135 if (err < 0)
3136 return err;
3137 }
3138 }
3139 }
Takashi Iwaibae84e72010-03-22 08:30:20 +01003140
3141 alc_free_kctls(codec); /* no longer needed */
3142
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 return 0;
3144}
3145
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003146
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147/*
3148 * initialize the codec volumes, etc
3149 */
3150
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003151/*
3152 * generic initialization of ADC, input mixers and output mixers
3153 */
3154static struct hda_verb alc880_volume_init_verbs[] = {
3155 /*
3156 * Unmute ADC0-2 and set the default input to mic-in
3157 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003158 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003159 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003160 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003161 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003162 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003163 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003165 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
3166 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003167 * Note: PASD motherboards uses the Line In 2 as the input for front
3168 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003170 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02003171 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3172 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3173 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3174 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3175 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
3176 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
3177 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003179 /*
3180 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003182 /* set vol=0 to output mixers */
3183 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3184 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3185 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3186 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3187 /* set up input amps for analog loopback */
3188 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003189 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3190 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02003191 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3192 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02003193 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3194 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02003195 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3196 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197
3198 { }
3199};
3200
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003201/*
3202 * 3-stack pin configuration:
3203 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
3204 */
3205static struct hda_verb alc880_pin_3stack_init_verbs[] = {
3206 /*
3207 * preset connection lists of input pins
3208 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
3209 */
3210 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
3211 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3212 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
3213
3214 /*
3215 * Set pin mode and muting
3216 */
3217 /* set front pin widgets 0x14 for output */
3218 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3219 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3220 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3221 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3222 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3223 /* Mic2 (as headphone out) for HP output */
3224 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3225 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3226 /* Line In pin widget for input */
3227 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3228 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3229 /* Line2 (as front mic) pin widget for input and vref at 80% */
3230 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3231 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3232 /* CD pin widget for input */
3233 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3234
3235 { }
3236};
3237
3238/*
3239 * 5-stack pin configuration:
3240 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
3241 * line-in/side = 0x1a, f-mic = 0x1b
3242 */
3243static struct hda_verb alc880_pin_5stack_init_verbs[] = {
3244 /*
3245 * preset connection lists of input pins
3246 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
3247 */
3248 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3249 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
3250
3251 /*
3252 * Set pin mode and muting
3253 */
3254 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02003255 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3256 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3257 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3258 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003259 /* unmute pins for output (no gain on this amp) */
3260 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3261 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3262 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3263 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3264
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02003266 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003267 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3268 /* Mic2 (as headphone out) for HP output */
3269 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02003270 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003271 /* Line In pin widget for input */
3272 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3273 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3274 /* Line2 (as front mic) pin widget for input and vref at 80% */
3275 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3276 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3277 /* CD pin widget for input */
3278 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279
3280 { }
3281};
3282
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003283/*
3284 * W810 pin configuration:
3285 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
3286 */
3287static struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288 /* hphone/speaker input selector: front DAC */
3289 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
3290
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003291 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3292 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3293 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3294 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3295 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3296 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3297
3298 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02003299 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003300
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301 { }
3302};
3303
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003304/*
3305 * Z71V pin configuration:
3306 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
3307 */
3308static struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003309 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003310 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02003311 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003312 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02003313
Takashi Iwai16ded522005-06-10 19:58:24 +02003314 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003315 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02003316 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003317 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02003318
3319 { }
3320};
3321
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003322/*
3323 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003324 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
3325 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003326 */
3327static struct hda_verb alc880_pin_6stack_init_verbs[] = {
3328 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3329
Takashi Iwai16ded522005-06-10 19:58:24 +02003330 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003331 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003332 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003333 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003334 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003335 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003336 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003337 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3338
Takashi Iwai16ded522005-06-10 19:58:24 +02003339 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003340 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003341 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003342 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003343 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003344 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003345 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02003346 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003347 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02003348
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003349 { }
3350};
Takashi Iwai16ded522005-06-10 19:58:24 +02003351
Kailang Yangccc656c2006-10-17 12:32:26 +02003352/*
3353 * Uniwill pin configuration:
3354 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
3355 * line = 0x1a
3356 */
3357static struct hda_verb alc880_uniwill_init_verbs[] = {
3358 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3359
3360 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3361 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3362 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3363 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3364 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3365 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3366 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3367 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3368 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3369 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3370 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3371 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3372 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3373 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3374
3375 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3376 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3377 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3378 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3379 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3380 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3381 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
3382 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
3383 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3384
3385 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3386 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
3387
3388 { }
3389};
3390
3391/*
3392* Uniwill P53
Kailang Yangea1fb292008-08-26 12:58:38 +02003393* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
Kailang Yangccc656c2006-10-17 12:32:26 +02003394 */
3395static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
3396 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3397
3398 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3399 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3400 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3401 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3402 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3403 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3404 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3405 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3406 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3407 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3408 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3409 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3410
3411 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3412 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3413 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3414 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3415 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3416 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3417
3418 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3419 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
3420
3421 { }
3422};
3423
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003424static struct hda_verb alc880_beep_init_verbs[] = {
3425 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
3426 { }
3427};
3428
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003429/* auto-toggle front mic */
Anisse Astiereeb43382010-12-16 12:19:47 +01003430static void alc88x_simple_mic_automute(struct hda_codec *codec)
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003431{
3432 unsigned int present;
3433 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02003434
Wu Fengguang864f92b2009-11-18 12:38:02 +08003435 present = snd_hda_jack_detect(codec, 0x18);
Takashi Iwai47fd8302007-08-10 17:11:07 +02003436 bits = present ? HDA_AMP_MUTE : 0;
3437 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003438}
3439
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003440static void alc880_uniwill_setup(struct hda_codec *codec)
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003441{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003442 struct alc_spec *spec = codec->spec;
3443
3444 spec->autocfg.hp_pins[0] = 0x14;
3445 spec->autocfg.speaker_pins[0] = 0x15;
3446 spec->autocfg.speaker_pins[0] = 0x16;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003447}
3448
3449static void alc880_uniwill_init_hook(struct hda_codec *codec)
3450{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003451 alc_automute_amp(codec);
Anisse Astiereeb43382010-12-16 12:19:47 +01003452 alc88x_simple_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02003453}
3454
3455static void alc880_uniwill_unsol_event(struct hda_codec *codec,
3456 unsigned int res)
3457{
3458 /* Looks like the unsol event is incompatible with the standard
3459 * definition. 4bit tag is placed at 28 bit!
3460 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003461 switch (res >> 28) {
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003462 case ALC880_MIC_EVENT:
Anisse Astiereeb43382010-12-16 12:19:47 +01003463 alc88x_simple_mic_automute(codec);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003464 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003465 default:
3466 alc_automute_amp_unsol_event(codec, res);
3467 break;
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003468 }
Kailang Yangccc656c2006-10-17 12:32:26 +02003469}
3470
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003471static void alc880_uniwill_p53_setup(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02003472{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003473 struct alc_spec *spec = codec->spec;
Kailang Yangccc656c2006-10-17 12:32:26 +02003474
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003475 spec->autocfg.hp_pins[0] = 0x14;
3476 spec->autocfg.speaker_pins[0] = 0x15;
Kailang Yangccc656c2006-10-17 12:32:26 +02003477}
3478
3479static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
3480{
3481 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02003482
Kailang Yangccc656c2006-10-17 12:32:26 +02003483 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02003484 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
3485 present &= HDA_AMP_VOLMASK;
3486 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
3487 HDA_AMP_VOLMASK, present);
3488 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
3489 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02003490}
Takashi Iwai47fd8302007-08-10 17:11:07 +02003491
Kailang Yangccc656c2006-10-17 12:32:26 +02003492static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
3493 unsigned int res)
3494{
3495 /* Looks like the unsol event is incompatible with the standard
3496 * definition. 4bit tag is placed at 28 bit!
3497 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003498 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02003499 alc880_uniwill_p53_dcvol_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003500 else
3501 alc_automute_amp_unsol_event(codec, res);
Kailang Yangccc656c2006-10-17 12:32:26 +02003502}
3503
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003504/*
3505 * F1734 pin configuration:
3506 * HP = 0x14, speaker-out = 0x15, mic = 0x18
3507 */
3508static struct hda_verb alc880_pin_f1734_init_verbs[] = {
Michael Gruberee7a9c72008-03-10 11:30:59 +01003509 {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003510 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
3511 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
3512 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
3513 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
3514
3515 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3516 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3517 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3518 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3519
3520 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3521 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Michael Gruberee7a9c72008-03-10 11:30:59 +01003522 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003523 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3524 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3525 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3526 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3527 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3528 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02003529
Takashi Iwai937b4162008-02-11 14:52:36 +01003530 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
3531 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
3532
Takashi Iwai16ded522005-06-10 19:58:24 +02003533 { }
3534};
3535
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003536/*
3537 * ASUS pin configuration:
3538 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
3539 */
3540static struct hda_verb alc880_pin_asus_init_verbs[] = {
3541 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
3542 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
3543 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
3544 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
3545
3546 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3547 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3548 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3549 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3550 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3551 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3552 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3553 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3554
3555 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3556 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3557 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3558 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3559 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3560 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3561 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3562 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3563 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02003564
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003565 { }
3566};
3567
3568/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003569#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
3570#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
David Heidelberger64a8be72009-06-08 16:15:18 +02003571#define alc880_gpio3_init_verbs alc_gpio3_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003572
Kailang Yangdf694da2005-12-05 19:42:22 +01003573/* Clevo m520g init */
3574static struct hda_verb alc880_pin_clevo_init_verbs[] = {
3575 /* headphone output */
3576 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3577 /* line-out */
3578 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3579 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3580 /* Line-in */
3581 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3582 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3583 /* CD */
3584 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3585 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3586 /* Mic1 (rear panel) */
3587 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3588 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3589 /* Mic2 (front panel) */
3590 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3591 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3592 /* headphone */
3593 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3594 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3595 /* change to EAPD mode */
3596 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3597 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3598
3599 { }
3600};
3601
3602static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02003603 /* change to EAPD mode */
3604 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3605 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3606
Kailang Yangdf694da2005-12-05 19:42:22 +01003607 /* Headphone output */
3608 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3609 /* Front output*/
3610 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3611 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
3612
3613 /* Line In pin widget for input */
3614 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3615 /* CD pin widget for input */
3616 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3617 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3618 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3619
3620 /* change to EAPD mode */
3621 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3622 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
3623
3624 { }
3625};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003626
3627/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003628 * LG m1 express dual
3629 *
3630 * Pin assignment:
3631 * Rear Line-In/Out (blue): 0x14
3632 * Build-in Mic-In: 0x15
3633 * Speaker-out: 0x17
3634 * HP-Out (green): 0x1b
3635 * Mic-In/Out (red): 0x19
3636 * SPDIF-Out: 0x1e
3637 */
3638
3639/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
3640static hda_nid_t alc880_lg_dac_nids[3] = {
3641 0x05, 0x02, 0x03
3642};
3643
3644/* seems analog CD is not working */
3645static struct hda_input_mux alc880_lg_capture_source = {
3646 .num_items = 3,
3647 .items = {
3648 { "Mic", 0x1 },
3649 { "Line", 0x5 },
3650 { "Internal Mic", 0x6 },
3651 },
3652};
3653
3654/* 2,4,6 channel modes */
3655static struct hda_verb alc880_lg_ch2_init[] = {
3656 /* set line-in and mic-in to input */
3657 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
3658 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3659 { }
3660};
3661
3662static struct hda_verb alc880_lg_ch4_init[] = {
3663 /* set line-in to out and mic-in to input */
3664 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3665 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3666 { }
3667};
3668
3669static struct hda_verb alc880_lg_ch6_init[] = {
3670 /* set line-in and mic-in to output */
3671 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3672 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3673 { }
3674};
3675
3676static struct hda_channel_mode alc880_lg_ch_modes[3] = {
3677 { 2, alc880_lg_ch2_init },
3678 { 4, alc880_lg_ch4_init },
3679 { 6, alc880_lg_ch6_init },
3680};
3681
3682static struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003683 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
3684 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003685 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3686 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
3687 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
3688 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
3689 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
3690 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
3691 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3692 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
3693 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
3694 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
3695 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
3696 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
3697 {
3698 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3699 .name = "Channel Mode",
3700 .info = alc_ch_mode_info,
3701 .get = alc_ch_mode_get,
3702 .put = alc_ch_mode_put,
3703 },
3704 { } /* end */
3705};
3706
3707static struct hda_verb alc880_lg_init_verbs[] = {
3708 /* set capture source to mic-in */
3709 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3710 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3711 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3712 /* mute all amp mixer inputs */
3713 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02003714 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
3715 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003716 /* line-in to input */
3717 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3718 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3719 /* built-in mic */
3720 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3721 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3722 /* speaker-out */
3723 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3724 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3725 /* mic-in to input */
3726 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3727 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3728 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3729 /* HP-out */
3730 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
3731 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3732 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3733 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003734 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003735 { }
3736};
3737
3738/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003739static void alc880_lg_setup(struct hda_codec *codec)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003740{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003741 struct alc_spec *spec = codec->spec;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003742
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003743 spec->autocfg.hp_pins[0] = 0x1b;
3744 spec->autocfg.speaker_pins[0] = 0x17;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003745}
3746
3747/*
Takashi Iwaid6815182006-03-23 16:06:23 +01003748 * LG LW20
3749 *
3750 * Pin assignment:
3751 * Speaker-out: 0x14
3752 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003753 * Built-in Mic-In: 0x19
3754 * Line-In: 0x1b
3755 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01003756 * SPDIF-Out: 0x1e
3757 */
3758
Takashi Iwaid6815182006-03-23 16:06:23 +01003759static struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003760 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01003761 .items = {
3762 { "Mic", 0x0 },
3763 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003764 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003765 },
3766};
3767
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003768#define alc880_lg_lw_modes alc880_threestack_modes
3769
Takashi Iwaid6815182006-03-23 16:06:23 +01003770static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003771 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3772 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
3773 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
3774 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
3775 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
3776 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
3777 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
3778 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
3779 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
3780 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01003781 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3782 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3783 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
3784 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003785 {
3786 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3787 .name = "Channel Mode",
3788 .info = alc_ch_mode_info,
3789 .get = alc_ch_mode_get,
3790 .put = alc_ch_mode_put,
3791 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003792 { } /* end */
3793};
3794
3795static struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003796 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3797 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
3798 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
3799
Takashi Iwaid6815182006-03-23 16:06:23 +01003800 /* set capture source to mic-in */
3801 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3802 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3803 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02003804 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01003805 /* speaker-out */
3806 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3807 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3808 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01003809 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3810 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3811 /* mic-in to input */
3812 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3813 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3814 /* built-in mic */
3815 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3816 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3817 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003818 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaid6815182006-03-23 16:06:23 +01003819 { }
3820};
3821
3822/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003823static void alc880_lg_lw_setup(struct hda_codec *codec)
Takashi Iwaid6815182006-03-23 16:06:23 +01003824{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003825 struct alc_spec *spec = codec->spec;
Takashi Iwaid6815182006-03-23 16:06:23 +01003826
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003827 spec->autocfg.hp_pins[0] = 0x1b;
3828 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid6815182006-03-23 16:06:23 +01003829}
3830
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003831static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
3832 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3833 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
3834 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3835 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3836 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3837 HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
3838 { } /* end */
3839};
3840
3841static struct hda_input_mux alc880_medion_rim_capture_source = {
3842 .num_items = 2,
3843 .items = {
3844 { "Mic", 0x0 },
3845 { "Internal Mic", 0x1 },
3846 },
3847};
3848
3849static struct hda_verb alc880_medion_rim_init_verbs[] = {
3850 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3851
3852 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3853 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3854
3855 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3856 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3857 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3858 /* Mic2 (as headphone out) for HP output */
3859 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3860 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3861 /* Internal Speaker */
3862 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3863 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3864
3865 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3866 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3867
3868 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3869 { }
3870};
3871
3872/* toggle speaker-output according to the hp-jack state */
3873static void alc880_medion_rim_automute(struct hda_codec *codec)
3874{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003875 struct alc_spec *spec = codec->spec;
3876 alc_automute_amp(codec);
3877 /* toggle EAPD */
3878 if (spec->jack_present)
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003879 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
3880 else
3881 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
3882}
3883
3884static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
3885 unsigned int res)
3886{
3887 /* Looks like the unsol event is incompatible with the standard
3888 * definition. 4bit tag is placed at 28 bit!
3889 */
3890 if ((res >> 28) == ALC880_HP_EVENT)
3891 alc880_medion_rim_automute(codec);
3892}
3893
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003894static void alc880_medion_rim_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003895{
3896 struct alc_spec *spec = codec->spec;
3897
3898 spec->autocfg.hp_pins[0] = 0x14;
3899 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003900}
3901
Takashi Iwaicb53c622007-08-10 17:21:45 +02003902#ifdef CONFIG_SND_HDA_POWER_SAVE
3903static struct hda_amp_list alc880_loopbacks[] = {
3904 { 0x0b, HDA_INPUT, 0 },
3905 { 0x0b, HDA_INPUT, 1 },
3906 { 0x0b, HDA_INPUT, 2 },
3907 { 0x0b, HDA_INPUT, 3 },
3908 { 0x0b, HDA_INPUT, 4 },
3909 { } /* end */
3910};
3911
3912static struct hda_amp_list alc880_lg_loopbacks[] = {
3913 { 0x0b, HDA_INPUT, 1 },
3914 { 0x0b, HDA_INPUT, 6 },
3915 { 0x0b, HDA_INPUT, 7 },
3916 { } /* end */
3917};
3918#endif
3919
Takashi Iwaid6815182006-03-23 16:06:23 +01003920/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003921 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003922 */
Takashi Iwai16ded522005-06-10 19:58:24 +02003923
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924static int alc_init(struct hda_codec *codec)
3925{
3926 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003927 unsigned int i;
3928
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02003929 alc_fix_pll(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02003930 alc_auto_init_amp(codec, spec->init_amp);
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02003931
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003932 for (i = 0; i < spec->num_init_verbs; i++)
3933 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003934
3935 if (spec->init_hook)
3936 spec->init_hook(codec);
3937
Takashi Iwai58701122011-01-13 15:41:45 +01003938 alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT);
3939
Takashi Iwai9e5341b2010-09-21 09:57:06 +02003940 hda_call_check_power_status(codec, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003941 return 0;
3942}
3943
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003944static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
3945{
3946 struct alc_spec *spec = codec->spec;
3947
3948 if (spec->unsol_event)
3949 spec->unsol_event(codec, res);
3950}
3951
Takashi Iwaicb53c622007-08-10 17:21:45 +02003952#ifdef CONFIG_SND_HDA_POWER_SAVE
3953static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
3954{
3955 struct alc_spec *spec = codec->spec;
3956 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
3957}
3958#endif
3959
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960/*
3961 * Analog playback callbacks
3962 */
3963static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
3964 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003965 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966{
3967 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01003968 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
3969 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970}
3971
3972static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
3973 struct hda_codec *codec,
3974 unsigned int stream_tag,
3975 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003976 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977{
3978 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003979 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
3980 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003981}
3982
3983static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3984 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003985 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003986{
3987 struct alc_spec *spec = codec->spec;
3988 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
3989}
3990
3991/*
3992 * Digital out
3993 */
3994static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
3995 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003996 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003997{
3998 struct alc_spec *spec = codec->spec;
3999 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
4000}
4001
Takashi Iwai6b97eb42007-04-05 14:51:48 +02004002static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
4003 struct hda_codec *codec,
4004 unsigned int stream_tag,
4005 unsigned int format,
4006 struct snd_pcm_substream *substream)
4007{
4008 struct alc_spec *spec = codec->spec;
4009 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
4010 stream_tag, format, substream);
4011}
4012
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01004013static int alc880_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
4014 struct hda_codec *codec,
4015 struct snd_pcm_substream *substream)
4016{
4017 struct alc_spec *spec = codec->spec;
4018 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
4019}
4020
Linus Torvalds1da177e2005-04-16 15:20:36 -07004021static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
4022 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004023 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024{
4025 struct alc_spec *spec = codec->spec;
4026 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
4027}
4028
4029/*
4030 * Analog capture
4031 */
Takashi Iwai63300792008-01-24 15:31:36 +01004032static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033 struct hda_codec *codec,
4034 unsigned int stream_tag,
4035 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004036 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037{
4038 struct alc_spec *spec = codec->spec;
4039
Takashi Iwai63300792008-01-24 15:31:36 +01004040 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041 stream_tag, 0, format);
4042 return 0;
4043}
4044
Takashi Iwai63300792008-01-24 15:31:36 +01004045static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004047 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048{
4049 struct alc_spec *spec = codec->spec;
4050
Takashi Iwai888afa12008-03-18 09:57:50 +01004051 snd_hda_codec_cleanup_stream(codec,
4052 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004053 return 0;
4054}
4055
Takashi Iwai840b64c2010-07-13 22:49:01 +02004056/* analog capture with dynamic dual-adc changes */
4057static int dualmic_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
4058 struct hda_codec *codec,
4059 unsigned int stream_tag,
4060 unsigned int format,
4061 struct snd_pcm_substream *substream)
4062{
4063 struct alc_spec *spec = codec->spec;
4064 spec->cur_adc = spec->adc_nids[spec->cur_adc_idx];
4065 spec->cur_adc_stream_tag = stream_tag;
4066 spec->cur_adc_format = format;
4067 snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
4068 return 0;
4069}
4070
4071static int dualmic_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
4072 struct hda_codec *codec,
4073 struct snd_pcm_substream *substream)
4074{
4075 struct alc_spec *spec = codec->spec;
4076 snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
4077 spec->cur_adc = 0;
4078 return 0;
4079}
4080
4081static struct hda_pcm_stream dualmic_pcm_analog_capture = {
4082 .substreams = 1,
4083 .channels_min = 2,
4084 .channels_max = 2,
4085 .nid = 0, /* fill later */
4086 .ops = {
4087 .prepare = dualmic_capture_pcm_prepare,
4088 .cleanup = dualmic_capture_pcm_cleanup
4089 },
4090};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091
4092/*
4093 */
4094static struct hda_pcm_stream alc880_pcm_analog_playback = {
4095 .substreams = 1,
4096 .channels_min = 2,
4097 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004098 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004099 .ops = {
4100 .open = alc880_playback_pcm_open,
4101 .prepare = alc880_playback_pcm_prepare,
4102 .cleanup = alc880_playback_pcm_cleanup
4103 },
4104};
4105
4106static struct hda_pcm_stream alc880_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01004107 .substreams = 1,
4108 .channels_min = 2,
4109 .channels_max = 2,
4110 /* NID is set in alc_build_pcms */
4111};
4112
4113static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
4114 .substreams = 1,
4115 .channels_min = 2,
4116 .channels_max = 2,
4117 /* NID is set in alc_build_pcms */
4118};
4119
4120static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
4121 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122 .channels_min = 2,
4123 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004124 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004125 .ops = {
Takashi Iwai63300792008-01-24 15:31:36 +01004126 .prepare = alc880_alt_capture_pcm_prepare,
4127 .cleanup = alc880_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128 },
4129};
4130
4131static struct hda_pcm_stream alc880_pcm_digital_playback = {
4132 .substreams = 1,
4133 .channels_min = 2,
4134 .channels_max = 2,
4135 /* NID is set in alc_build_pcms */
4136 .ops = {
4137 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02004138 .close = alc880_dig_playback_pcm_close,
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01004139 .prepare = alc880_dig_playback_pcm_prepare,
4140 .cleanup = alc880_dig_playback_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141 },
4142};
4143
4144static struct hda_pcm_stream alc880_pcm_digital_capture = {
4145 .substreams = 1,
4146 .channels_min = 2,
4147 .channels_max = 2,
4148 /* NID is set in alc_build_pcms */
4149};
4150
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004151/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwai63300792008-01-24 15:31:36 +01004152static struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004153 .substreams = 0,
4154 .channels_min = 0,
4155 .channels_max = 0,
4156};
4157
Linus Torvalds1da177e2005-04-16 15:20:36 -07004158static int alc_build_pcms(struct hda_codec *codec)
4159{
4160 struct alc_spec *spec = codec->spec;
4161 struct hda_pcm *info = spec->pcm_rec;
4162 int i;
4163
4164 codec->num_pcms = 1;
4165 codec->pcm_info = info;
4166
Takashi Iwaie64f14f2009-01-20 18:32:55 +01004167 if (spec->no_analog)
4168 goto skip_analog;
4169
Takashi Iwai812a2cc2009-05-16 10:00:49 +02004170 snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog),
4171 "%s Analog", codec->chip_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172 info->name = spec->stream_name_analog;
Kailang Yang274693f2009-12-03 10:07:50 +01004173
Takashi Iwai4a471b72005-12-07 13:56:29 +01004174 if (spec->stream_analog_playback) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02004175 if (snd_BUG_ON(!spec->multiout.dac_nids))
4176 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004177 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
4178 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
4179 }
4180 if (spec->stream_analog_capture) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02004181 if (snd_BUG_ON(!spec->adc_nids))
4182 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004183 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
4184 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
4185 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186
Takashi Iwai4a471b72005-12-07 13:56:29 +01004187 if (spec->channel_mode) {
4188 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
4189 for (i = 0; i < spec->num_channel_mode; i++) {
4190 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
4191 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
4192 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193 }
4194 }
4195
Takashi Iwaie64f14f2009-01-20 18:32:55 +01004196 skip_analog:
Takashi Iwaie08a0072006-09-07 17:52:14 +02004197 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004198 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwai812a2cc2009-05-16 10:00:49 +02004199 snprintf(spec->stream_name_digital,
4200 sizeof(spec->stream_name_digital),
4201 "%s Digital", codec->chip_name);
Takashi Iwaie08a0072006-09-07 17:52:14 +02004202 codec->num_pcms = 2;
Wu Fengguangb25c9da2009-02-06 15:02:27 +08004203 codec->slave_dig_outs = spec->multiout.slave_dig_outs;
Takashi Iwaic06134d2006-10-11 18:49:13 +02004204 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004205 info->name = spec->stream_name_digital;
Takashi Iwai8c441982009-01-20 18:30:20 +01004206 if (spec->dig_out_type)
4207 info->pcm_type = spec->dig_out_type;
4208 else
4209 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004210 if (spec->multiout.dig_out_nid &&
4211 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004212 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
4213 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
4214 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01004215 if (spec->dig_in_nid &&
4216 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
4218 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
4219 }
Takashi Iwai963f8032008-08-11 10:04:40 +02004220 /* FIXME: do we need this for all Realtek codec models? */
4221 codec->spdif_status_reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222 }
4223
Takashi Iwaie64f14f2009-01-20 18:32:55 +01004224 if (spec->no_analog)
4225 return 0;
4226
Takashi Iwaie08a0072006-09-07 17:52:14 +02004227 /* If the use of more than one ADC is requested for the current
4228 * model, configure a second analog capture-only PCM.
4229 */
4230 /* Additional Analaog capture for index #2 */
Takashi Iwai63300792008-01-24 15:31:36 +01004231 if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
4232 (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02004233 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02004234 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02004235 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01004236 if (spec->alt_dac_nid) {
4237 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
4238 *spec->stream_analog_alt_playback;
4239 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
4240 spec->alt_dac_nid;
4241 } else {
4242 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
4243 alc_pcm_null_stream;
4244 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
4245 }
4246 if (spec->num_adc_nids > 1) {
4247 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
4248 *spec->stream_analog_alt_capture;
4249 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
4250 spec->adc_nids[1];
4251 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
4252 spec->num_adc_nids - 1;
4253 } else {
4254 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
4255 alc_pcm_null_stream;
4256 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02004257 }
4258 }
4259
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260 return 0;
4261}
4262
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004263static inline void alc_shutup(struct hda_codec *codec)
4264{
4265 snd_hda_shutup_pins(codec);
4266}
4267
Takashi Iwai603c4012008-07-30 15:01:44 +02004268static void alc_free_kctls(struct hda_codec *codec)
4269{
4270 struct alc_spec *spec = codec->spec;
4271
4272 if (spec->kctls.list) {
4273 struct snd_kcontrol_new *kctl = spec->kctls.list;
4274 int i;
4275 for (i = 0; i < spec->kctls.used; i++)
4276 kfree(kctl[i].name);
4277 }
4278 snd_array_free(&spec->kctls);
4279}
4280
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281static void alc_free(struct hda_codec *codec)
4282{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004283 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004284
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004285 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004286 return;
4287
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004288 alc_shutup(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +02004289 alc_free_kctls(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004290 kfree(spec);
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09004291 snd_hda_detach_beep_device(codec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292}
4293
Hector Martinf5de24b2009-12-20 22:51:31 +01004294#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -05004295static void alc_power_eapd(struct hda_codec *codec)
4296{
4297 /* We currently only handle front, HP */
4298 switch (codec->vendor_id) {
4299 case 0x10ec0260:
Takashi Iwai9e4c8492010-01-19 15:53:43 +01004300 set_eapd(codec, 0x0f, 0);
4301 set_eapd(codec, 0x10, 0);
Daniel T Chenc97259d2009-12-27 18:52:08 -05004302 break;
4303 case 0x10ec0262:
4304 case 0x10ec0267:
4305 case 0x10ec0268:
4306 case 0x10ec0269:
Takashi Iwai9e4c8492010-01-19 15:53:43 +01004307 case 0x10ec0270:
Daniel T Chenc97259d2009-12-27 18:52:08 -05004308 case 0x10ec0272:
4309 case 0x10ec0660:
4310 case 0x10ec0662:
4311 case 0x10ec0663:
4312 case 0x10ec0862:
4313 case 0x10ec0889:
Takashi Iwai9e4c8492010-01-19 15:53:43 +01004314 set_eapd(codec, 0x14, 0);
4315 set_eapd(codec, 0x15, 0);
Daniel T Chenc97259d2009-12-27 18:52:08 -05004316 break;
4317 }
4318}
4319
Hector Martinf5de24b2009-12-20 22:51:31 +01004320static int alc_suspend(struct hda_codec *codec, pm_message_t state)
4321{
4322 struct alc_spec *spec = codec->spec;
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004323 alc_shutup(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01004324 if (spec && spec->power_hook)
Daniel T Chenc97259d2009-12-27 18:52:08 -05004325 spec->power_hook(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01004326 return 0;
4327}
4328#endif
4329
Takashi Iwaie044c392008-10-27 16:56:24 +01004330#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaie044c392008-10-27 16:56:24 +01004331static int alc_resume(struct hda_codec *codec)
4332{
Takashi Iwaie044c392008-10-27 16:56:24 +01004333 codec->patch_ops.init(codec);
4334 snd_hda_codec_resume_amp(codec);
4335 snd_hda_codec_resume_cache(codec);
Takashi Iwai9e5341b2010-09-21 09:57:06 +02004336 hda_call_check_power_status(codec, 0x01);
Takashi Iwaie044c392008-10-27 16:56:24 +01004337 return 0;
4338}
Takashi Iwaie044c392008-10-27 16:56:24 +01004339#endif
4340
Linus Torvalds1da177e2005-04-16 15:20:36 -07004341/*
4342 */
4343static struct hda_codec_ops alc_patch_ops = {
4344 .build_controls = alc_build_controls,
4345 .build_pcms = alc_build_pcms,
4346 .init = alc_init,
4347 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004348 .unsol_event = alc_unsol_event,
Takashi Iwaie044c392008-10-27 16:56:24 +01004349#ifdef SND_HDA_NEEDS_RESUME
4350 .resume = alc_resume,
4351#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02004352#ifdef CONFIG_SND_HDA_POWER_SAVE
Hector Martinf5de24b2009-12-20 22:51:31 +01004353 .suspend = alc_suspend,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004354 .check_power_status = alc_check_power_status,
4355#endif
Daniel T Chenc97259d2009-12-27 18:52:08 -05004356 .reboot_notify = alc_shutup,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004357};
4358
Kailang Yangc027ddc2010-03-19 11:33:06 +01004359/* replace the codec chip_name with the given string */
4360static int alc_codec_rename(struct hda_codec *codec, const char *name)
4361{
4362 kfree(codec->chip_name);
4363 codec->chip_name = kstrdup(name, GFP_KERNEL);
4364 if (!codec->chip_name) {
4365 alc_free(codec);
4366 return -ENOMEM;
4367 }
4368 return 0;
4369}
4370
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004371/*
4372 * Test configuration for debugging
4373 *
4374 * Almost all inputs/outputs are enabled. I/O pins can be configured via
4375 * enum controls.
4376 */
4377#ifdef CONFIG_SND_DEBUG
4378static hda_nid_t alc880_test_dac_nids[4] = {
4379 0x02, 0x03, 0x04, 0x05
4380};
4381
4382static struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004383 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004384 .items = {
4385 { "In-1", 0x0 },
4386 { "In-2", 0x1 },
4387 { "In-3", 0x2 },
4388 { "In-4", 0x3 },
4389 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004390 { "Front", 0x5 },
4391 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004392 },
4393};
4394
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01004395static struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004396 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02004397 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004398 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02004399 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004400};
4401
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004402static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
4403 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004404{
4405 static char *texts[] = {
4406 "N/A", "Line Out", "HP Out",
4407 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
4408 };
4409 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
4410 uinfo->count = 1;
4411 uinfo->value.enumerated.items = 8;
4412 if (uinfo->value.enumerated.item >= 8)
4413 uinfo->value.enumerated.item = 7;
4414 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
4415 return 0;
4416}
4417
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004418static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
4419 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004420{
4421 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4422 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4423 unsigned int pin_ctl, item = 0;
4424
4425 pin_ctl = snd_hda_codec_read(codec, nid, 0,
4426 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
4427 if (pin_ctl & AC_PINCTL_OUT_EN) {
4428 if (pin_ctl & AC_PINCTL_HP_EN)
4429 item = 2;
4430 else
4431 item = 1;
4432 } else if (pin_ctl & AC_PINCTL_IN_EN) {
4433 switch (pin_ctl & AC_PINCTL_VREFEN) {
4434 case AC_PINCTL_VREF_HIZ: item = 3; break;
4435 case AC_PINCTL_VREF_50: item = 4; break;
4436 case AC_PINCTL_VREF_GRD: item = 5; break;
4437 case AC_PINCTL_VREF_80: item = 6; break;
4438 case AC_PINCTL_VREF_100: item = 7; break;
4439 }
4440 }
4441 ucontrol->value.enumerated.item[0] = item;
4442 return 0;
4443}
4444
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004445static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
4446 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004447{
4448 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4449 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4450 static unsigned int ctls[] = {
4451 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
4452 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
4453 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
4454 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
4455 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
4456 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
4457 };
4458 unsigned int old_ctl, new_ctl;
4459
4460 old_ctl = snd_hda_codec_read(codec, nid, 0,
4461 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
4462 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
4463 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004464 int val;
4465 snd_hda_codec_write_cache(codec, nid, 0,
4466 AC_VERB_SET_PIN_WIDGET_CONTROL,
4467 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02004468 val = ucontrol->value.enumerated.item[0] >= 3 ?
4469 HDA_AMP_MUTE : 0;
4470 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
4471 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004472 return 1;
4473 }
4474 return 0;
4475}
4476
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004477static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
4478 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004479{
4480 static char *texts[] = {
4481 "Front", "Surround", "CLFE", "Side"
4482 };
4483 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
4484 uinfo->count = 1;
4485 uinfo->value.enumerated.items = 4;
4486 if (uinfo->value.enumerated.item >= 4)
4487 uinfo->value.enumerated.item = 3;
4488 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
4489 return 0;
4490}
4491
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004492static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
4493 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004494{
4495 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4496 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4497 unsigned int sel;
4498
4499 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
4500 ucontrol->value.enumerated.item[0] = sel & 3;
4501 return 0;
4502}
4503
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004504static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
4505 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004506{
4507 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4508 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4509 unsigned int sel;
4510
4511 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
4512 if (ucontrol->value.enumerated.item[0] != sel) {
4513 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004514 snd_hda_codec_write_cache(codec, nid, 0,
4515 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004516 return 1;
4517 }
4518 return 0;
4519}
4520
4521#define PIN_CTL_TEST(xname,nid) { \
4522 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
4523 .name = xname, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01004524 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004525 .info = alc_test_pin_ctl_info, \
4526 .get = alc_test_pin_ctl_get, \
4527 .put = alc_test_pin_ctl_put, \
4528 .private_value = nid \
4529 }
4530
4531#define PIN_SRC_TEST(xname,nid) { \
4532 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
4533 .name = xname, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01004534 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004535 .info = alc_test_pin_src_info, \
4536 .get = alc_test_pin_src_get, \
4537 .put = alc_test_pin_src_put, \
4538 .private_value = nid \
4539 }
4540
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004541static struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02004542 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
4543 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
4544 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
4545 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004546 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
4547 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
4548 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
4549 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004550 PIN_CTL_TEST("Front Pin Mode", 0x14),
4551 PIN_CTL_TEST("Surround Pin Mode", 0x15),
4552 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
4553 PIN_CTL_TEST("Side Pin Mode", 0x17),
4554 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
4555 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
4556 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
4557 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
4558 PIN_SRC_TEST("In-1 Pin Source", 0x18),
4559 PIN_SRC_TEST("In-2 Pin Source", 0x19),
4560 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
4561 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
4562 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
4563 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
4564 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
4565 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
4566 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
4567 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
4568 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
4569 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
4570 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
4571 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004572 {
4573 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4574 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01004575 .info = alc_ch_mode_info,
4576 .get = alc_ch_mode_get,
4577 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004578 },
4579 { } /* end */
4580};
4581
4582static struct hda_verb alc880_test_init_verbs[] = {
4583 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02004584 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4585 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4586 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4587 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4588 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4589 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4590 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4591 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004592 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02004593 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4594 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4595 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4596 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004597 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004598 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4599 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4600 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4601 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004602 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004603 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4604 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4605 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4606 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004607 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02004608 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4609 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02004610 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4611 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4612 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004613 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02004614 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4615 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4616 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4617 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004618 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02004619 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004620 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004621 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004622 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004623 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004624 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004625 /* Analog input/passthru */
4626 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4627 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4628 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4629 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4630 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004631 { }
4632};
4633#endif
4634
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635/*
4636 */
4637
Takashi Iwaiea734962011-01-17 11:29:34 +01004638static const char * const alc880_models[ALC880_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004639 [ALC880_3ST] = "3stack",
4640 [ALC880_TCL_S700] = "tcl",
4641 [ALC880_3ST_DIG] = "3stack-digout",
4642 [ALC880_CLEVO] = "clevo",
4643 [ALC880_5ST] = "5stack",
4644 [ALC880_5ST_DIG] = "5stack-digout",
4645 [ALC880_W810] = "w810",
4646 [ALC880_Z71V] = "z71v",
4647 [ALC880_6ST] = "6stack",
4648 [ALC880_6ST_DIG] = "6stack-digout",
4649 [ALC880_ASUS] = "asus",
4650 [ALC880_ASUS_W1V] = "asus-w1v",
4651 [ALC880_ASUS_DIG] = "asus-dig",
4652 [ALC880_ASUS_DIG2] = "asus-dig2",
4653 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004654 [ALC880_UNIWILL_P53] = "uniwill-p53",
4655 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004656 [ALC880_F1734] = "F1734",
4657 [ALC880_LG] = "lg",
4658 [ALC880_LG_LW] = "lg-lw",
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004659 [ALC880_MEDION_RIM] = "medion",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004660#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004661 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004662#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004663 [ALC880_AUTO] = "auto",
4664};
4665
4666static struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004667 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004668 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
4669 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
4670 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
4671 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
4672 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
4673 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
4674 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
4675 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004676 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
4677 SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004678 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
4679 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
4680 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
4681 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
4682 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
4683 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
4684 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
4685 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
4686 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
4687 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Travis Place186c3112008-05-20 11:54:41 +02004688 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004689 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
4690 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
4691 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004692 SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004693 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004694 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
4695 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004696 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
4697 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004698 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
4699 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
4700 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
4701 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004702 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
4703 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004704 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004705 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004706 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004707 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004708 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
4709 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004710 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004711 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004712 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004713 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004714 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Travis Place1d116042008-06-23 11:42:30 +02004715 SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
Daniel T Chen33535412010-04-22 07:15:26 -04004716 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_F1734),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004717 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004718 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004719 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
Daniel T Chen77c4d5c2010-12-02 22:45:45 -05004720 SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004721 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004722 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004723 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
4724 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
4725 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
4726 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004727 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
4728 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004729 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004730 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004731 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
4732 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004733 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
4734 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
4735 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004736 /* default Intel */
4737 SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004738 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
4739 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740 {}
4741};
4742
Takashi Iwai16ded522005-06-10 19:58:24 +02004743/*
Kailang Yangdf694da2005-12-05 19:42:22 +01004744 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02004745 */
Takashi Iwai16ded522005-06-10 19:58:24 +02004746static struct alc_config_preset alc880_presets[] = {
4747 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004748 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004749 .init_verbs = { alc880_volume_init_verbs,
4750 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004751 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02004752 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004753 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4754 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004755 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004756 .input_mux = &alc880_capture_source,
4757 },
4758 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004759 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004760 .init_verbs = { alc880_volume_init_verbs,
4761 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004762 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02004763 .dac_nids = alc880_dac_nids,
4764 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004765 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4766 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004767 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004768 .input_mux = &alc880_capture_source,
4769 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004770 [ALC880_TCL_S700] = {
4771 .mixers = { alc880_tcl_s700_mixer },
4772 .init_verbs = { alc880_volume_init_verbs,
4773 alc880_pin_tcl_S700_init_verbs,
4774 alc880_gpio2_init_verbs },
4775 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4776 .dac_nids = alc880_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004777 .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */
4778 .num_adc_nids = 1, /* single ADC */
Kailang Yangdf694da2005-12-05 19:42:22 +01004779 .hp_nid = 0x03,
4780 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4781 .channel_mode = alc880_2_jack_modes,
4782 .input_mux = &alc880_capture_source,
4783 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004784 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004785 .mixers = { alc880_three_stack_mixer,
4786 alc880_five_stack_mixer},
4787 .init_verbs = { alc880_volume_init_verbs,
4788 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004789 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4790 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004791 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
4792 .channel_mode = alc880_fivestack_modes,
4793 .input_mux = &alc880_capture_source,
4794 },
4795 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004796 .mixers = { alc880_three_stack_mixer,
4797 alc880_five_stack_mixer },
4798 .init_verbs = { alc880_volume_init_verbs,
4799 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004800 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4801 .dac_nids = alc880_dac_nids,
4802 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004803 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
4804 .channel_mode = alc880_fivestack_modes,
4805 .input_mux = &alc880_capture_source,
4806 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02004807 [ALC880_6ST] = {
4808 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004809 .init_verbs = { alc880_volume_init_verbs,
4810 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02004811 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
4812 .dac_nids = alc880_6st_dac_nids,
4813 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
4814 .channel_mode = alc880_sixstack_modes,
4815 .input_mux = &alc880_6stack_capture_source,
4816 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004817 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004818 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004819 .init_verbs = { alc880_volume_init_verbs,
4820 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004821 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
4822 .dac_nids = alc880_6st_dac_nids,
4823 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004824 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
4825 .channel_mode = alc880_sixstack_modes,
4826 .input_mux = &alc880_6stack_capture_source,
4827 },
4828 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004829 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004830 .init_verbs = { alc880_volume_init_verbs,
4831 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02004832 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004833 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
4834 .dac_nids = alc880_w810_dac_nids,
4835 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004836 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
4837 .channel_mode = alc880_w810_modes,
4838 .input_mux = &alc880_capture_source,
4839 },
4840 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004841 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004842 .init_verbs = { alc880_volume_init_verbs,
4843 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004844 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
4845 .dac_nids = alc880_z71v_dac_nids,
4846 .dig_out_nid = ALC880_DIGOUT_NID,
4847 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004848 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4849 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02004850 .input_mux = &alc880_capture_source,
4851 },
4852 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004853 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004854 .init_verbs = { alc880_volume_init_verbs,
4855 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004856 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
4857 .dac_nids = alc880_f1734_dac_nids,
4858 .hp_nid = 0x02,
4859 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4860 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01004861 .input_mux = &alc880_f1734_capture_source,
4862 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004863 .setup = alc880_uniwill_p53_setup,
4864 .init_hook = alc_automute_amp,
Takashi Iwai16ded522005-06-10 19:58:24 +02004865 },
4866 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004867 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004868 .init_verbs = { alc880_volume_init_verbs,
4869 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004870 alc880_gpio1_init_verbs },
4871 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4872 .dac_nids = alc880_asus_dac_nids,
4873 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4874 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004875 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004876 .input_mux = &alc880_capture_source,
4877 },
4878 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004879 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004880 .init_verbs = { alc880_volume_init_verbs,
4881 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004882 alc880_gpio1_init_verbs },
4883 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4884 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004885 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004886 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4887 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004888 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004889 .input_mux = &alc880_capture_source,
4890 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004891 [ALC880_ASUS_DIG2] = {
4892 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004893 .init_verbs = { alc880_volume_init_verbs,
4894 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01004895 alc880_gpio2_init_verbs }, /* use GPIO2 */
4896 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4897 .dac_nids = alc880_asus_dac_nids,
4898 .dig_out_nid = ALC880_DIGOUT_NID,
4899 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4900 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004901 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01004902 .input_mux = &alc880_capture_source,
4903 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004904 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004905 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004906 .init_verbs = { alc880_volume_init_verbs,
4907 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004908 alc880_gpio1_init_verbs },
4909 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4910 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004911 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004912 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4913 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004914 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004915 .input_mux = &alc880_capture_source,
4916 },
4917 [ALC880_UNIWILL_DIG] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004918 .mixers = { alc880_asus_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02004919 .init_verbs = { alc880_volume_init_verbs,
4920 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004921 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4922 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004923 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004924 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4925 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004926 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004927 .input_mux = &alc880_capture_source,
4928 },
Kailang Yangccc656c2006-10-17 12:32:26 +02004929 [ALC880_UNIWILL] = {
4930 .mixers = { alc880_uniwill_mixer },
4931 .init_verbs = { alc880_volume_init_verbs,
4932 alc880_uniwill_init_verbs },
4933 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4934 .dac_nids = alc880_asus_dac_nids,
4935 .dig_out_nid = ALC880_DIGOUT_NID,
4936 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4937 .channel_mode = alc880_threestack_modes,
4938 .need_dac_fix = 1,
4939 .input_mux = &alc880_capture_source,
4940 .unsol_event = alc880_uniwill_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004941 .setup = alc880_uniwill_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004942 .init_hook = alc880_uniwill_init_hook,
Kailang Yangccc656c2006-10-17 12:32:26 +02004943 },
4944 [ALC880_UNIWILL_P53] = {
4945 .mixers = { alc880_uniwill_p53_mixer },
4946 .init_verbs = { alc880_volume_init_verbs,
4947 alc880_uniwill_p53_init_verbs },
4948 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4949 .dac_nids = alc880_asus_dac_nids,
4950 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004951 .channel_mode = alc880_threestack_modes,
4952 .input_mux = &alc880_capture_source,
4953 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004954 .setup = alc880_uniwill_p53_setup,
4955 .init_hook = alc_automute_amp,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004956 },
4957 [ALC880_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004958 .mixers = { alc880_fujitsu_mixer },
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004959 .init_verbs = { alc880_volume_init_verbs,
4960 alc880_uniwill_p53_init_verbs,
4961 alc880_beep_init_verbs },
4962 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4963 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02004964 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004965 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4966 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02004967 .input_mux = &alc880_capture_source,
4968 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004969 .setup = alc880_uniwill_p53_setup,
4970 .init_hook = alc_automute_amp,
Kailang Yangccc656c2006-10-17 12:32:26 +02004971 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004972 [ALC880_CLEVO] = {
4973 .mixers = { alc880_three_stack_mixer },
4974 .init_verbs = { alc880_volume_init_verbs,
4975 alc880_pin_clevo_init_verbs },
4976 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4977 .dac_nids = alc880_dac_nids,
4978 .hp_nid = 0x03,
4979 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4980 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004981 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01004982 .input_mux = &alc880_capture_source,
4983 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004984 [ALC880_LG] = {
4985 .mixers = { alc880_lg_mixer },
4986 .init_verbs = { alc880_volume_init_verbs,
4987 alc880_lg_init_verbs },
4988 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
4989 .dac_nids = alc880_lg_dac_nids,
4990 .dig_out_nid = ALC880_DIGOUT_NID,
4991 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
4992 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004993 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004994 .input_mux = &alc880_lg_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004995 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004996 .setup = alc880_lg_setup,
4997 .init_hook = alc_automute_amp,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004998#ifdef CONFIG_SND_HDA_POWER_SAVE
4999 .loopbacks = alc880_lg_loopbacks,
5000#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005001 },
Takashi Iwaid6815182006-03-23 16:06:23 +01005002 [ALC880_LG_LW] = {
5003 .mixers = { alc880_lg_lw_mixer },
5004 .init_verbs = { alc880_volume_init_verbs,
5005 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02005006 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01005007 .dac_nids = alc880_dac_nids,
5008 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02005009 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
5010 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01005011 .input_mux = &alc880_lg_lw_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02005012 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005013 .setup = alc880_lg_lw_setup,
5014 .init_hook = alc_automute_amp,
Takashi Iwaid6815182006-03-23 16:06:23 +01005015 },
Takashi Iwaidf99cd32008-04-25 15:25:04 +02005016 [ALC880_MEDION_RIM] = {
5017 .mixers = { alc880_medion_rim_mixer },
5018 .init_verbs = { alc880_volume_init_verbs,
5019 alc880_medion_rim_init_verbs,
5020 alc_gpio2_init_verbs },
5021 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5022 .dac_nids = alc880_dac_nids,
5023 .dig_out_nid = ALC880_DIGOUT_NID,
5024 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
5025 .channel_mode = alc880_2_jack_modes,
5026 .input_mux = &alc880_medion_rim_capture_source,
5027 .unsol_event = alc880_medion_rim_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005028 .setup = alc880_medion_rim_setup,
5029 .init_hook = alc880_medion_rim_automute,
Takashi Iwaidf99cd32008-04-25 15:25:04 +02005030 },
Takashi Iwai16ded522005-06-10 19:58:24 +02005031#ifdef CONFIG_SND_DEBUG
5032 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005033 .mixers = { alc880_test_mixer },
5034 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005035 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
5036 .dac_nids = alc880_test_dac_nids,
5037 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02005038 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
5039 .channel_mode = alc880_test_modes,
5040 .input_mux = &alc880_test_capture_source,
5041 },
5042#endif
5043};
5044
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005045/*
5046 * Automatic parse of I/O pins from the BIOS configuration
5047 */
5048
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005049enum {
5050 ALC_CTL_WIDGET_VOL,
5051 ALC_CTL_WIDGET_MUTE,
5052 ALC_CTL_BIND_MUTE,
5053};
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01005054static struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005055 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
5056 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01005057 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005058};
5059
5060/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005061static int add_control(struct alc_spec *spec, int type, const char *name,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005062 int cidx, unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005063{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01005064 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005065
Takashi Iwai603c4012008-07-30 15:01:44 +02005066 snd_array_init(&spec->kctls, sizeof(*knew), 32);
5067 knew = snd_array_new(&spec->kctls);
5068 if (!knew)
5069 return -ENOMEM;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005070 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07005071 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005072 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005073 return -ENOMEM;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005074 knew->index = cidx;
Jaroslav Kysela4d02d1b2009-11-12 10:15:48 +01005075 if (get_amp_nid_(val))
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01005076 knew->subdevice = HDA_SUBDEV_AMP_FLAG;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005077 knew->private_value = val;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005078 return 0;
5079}
5080
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005081static int add_control_with_pfx(struct alc_spec *spec, int type,
5082 const char *pfx, const char *dir,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005083 const char *sfx, int cidx, unsigned long val)
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005084{
5085 char name[32];
5086 snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005087 return add_control(spec, type, name, cidx, val);
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005088}
5089
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005090#define add_pb_vol_ctrl(spec, type, pfx, val) \
5091 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
5092#define add_pb_sw_ctrl(spec, type, pfx, val) \
5093 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
5094#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \
5095 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
5096#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \
5097 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005098
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005099#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
5100#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
5101#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
5102#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005103#define alc880_idx_to_dac(nid) ((nid) + 0x02)
5104#define alc880_dac_to_idx(nid) ((nid) - 0x02)
5105#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
5106#define alc880_idx_to_selector(nid) ((nid) + 0x10)
5107#define ALC880_PIN_CD_NID 0x1c
5108
5109/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005110static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
5111 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005112{
5113 hda_nid_t nid;
5114 int assigned[4];
5115 int i, j;
5116
5117 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02005118 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005119
5120 /* check the pins hardwired to audio widget */
5121 for (i = 0; i < cfg->line_outs; i++) {
5122 nid = cfg->line_out_pins[i];
5123 if (alc880_is_fixed_pin(nid)) {
5124 int idx = alc880_fixed_pin_idx(nid);
Libin Yang5014f192005-11-23 15:48:36 +01005125 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005126 assigned[idx] = 1;
5127 }
5128 }
5129 /* left pins can be connect to any audio widget */
5130 for (i = 0; i < cfg->line_outs; i++) {
5131 nid = cfg->line_out_pins[i];
5132 if (alc880_is_fixed_pin(nid))
5133 continue;
5134 /* search for an empty channel */
5135 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005136 if (!assigned[j]) {
5137 spec->multiout.dac_nids[i] =
5138 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005139 assigned[j] = 1;
5140 break;
5141 }
5142 }
5143 }
5144 spec->multiout.num_dacs = cfg->line_outs;
5145 return 0;
5146}
5147
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005148static const char *alc_get_line_out_pfx(const struct auto_pin_cfg *cfg,
5149 bool can_be_master)
5150{
5151 if (!cfg->hp_outs && !cfg->speaker_outs && can_be_master)
5152 return "Master";
5153
5154 switch (cfg->line_out_type) {
5155 case AUTO_PIN_SPEAKER_OUT:
5156 return "Speaker";
5157 case AUTO_PIN_HP_OUT:
5158 return "Headphone";
5159 default:
5160 if (cfg->line_outs == 1)
5161 return "PCM";
5162 break;
5163 }
5164 return NULL;
5165}
5166
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005167/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01005168static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
5169 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005170{
Takashi Iwaiea734962011-01-17 11:29:34 +01005171 static const char * const chname[4] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005172 "Front", "Surround", NULL /*CLFE*/, "Side"
5173 };
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005174 const char *pfx = alc_get_line_out_pfx(cfg, false);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005175 hda_nid_t nid;
5176 int i, err;
5177
5178 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005179 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005180 continue;
5181 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005182 if (!pfx && i == 2) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005183 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005184 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
5185 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005186 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
5187 HDA_OUTPUT));
5188 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005189 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005190 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
5191 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005192 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
5193 HDA_OUTPUT));
5194 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005195 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005196 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
5197 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005198 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
5199 HDA_INPUT));
5200 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005201 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005202 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
5203 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005204 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
5205 HDA_INPUT));
5206 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005207 return err;
5208 } else {
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005209 const char *name = pfx;
5210 if (!name)
5211 name = chname[i];
5212 err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
5213 name, i,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005214 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
5215 HDA_OUTPUT));
5216 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005217 return err;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005218 err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
5219 name, i,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005220 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
5221 HDA_INPUT));
5222 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005223 return err;
5224 }
5225 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005226 return 0;
5227}
5228
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005229/* add playback controls for speaker and HP outputs */
5230static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
5231 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005232{
5233 hda_nid_t nid;
5234 int err;
5235
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005236 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005237 return 0;
5238
5239 if (alc880_is_fixed_pin(pin)) {
5240 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01005241 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005242 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005243 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01005244 else
5245 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005246 /* control HP volume/switch on the output mixer amp */
5247 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005248 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005249 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
5250 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005251 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005252 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005253 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
5254 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005255 return err;
5256 } else if (alc880_is_multi_pin(pin)) {
5257 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005258 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005259 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005260 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
5261 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005262 return err;
5263 }
5264 return 0;
5265}
5266
5267/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005268static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005269 const char *ctlname, int ctlidx,
Kailang Yangdf694da2005-12-05 19:42:22 +01005270 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005271{
Kailang Yangdf694da2005-12-05 19:42:22 +01005272 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005273
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005274 err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, ctlidx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005275 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
5276 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005277 return err;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005278 err = __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, ctlidx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005279 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
5280 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005281 return err;
5282 return 0;
5283}
5284
Takashi Iwai05f5f472009-08-25 13:10:18 +02005285static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005286{
Takashi Iwai05f5f472009-08-25 13:10:18 +02005287 unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
5288 return (pincap & AC_PINCAP_IN) != 0;
5289}
5290
5291/* create playback/capture controls for input pins */
5292static int alc_auto_create_input_ctls(struct hda_codec *codec,
5293 const struct auto_pin_cfg *cfg,
5294 hda_nid_t mixer,
5295 hda_nid_t cap1, hda_nid_t cap2)
5296{
5297 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005298 struct hda_input_mux *imux = &spec->private_imux[0];
David Henningsson5322bf22011-01-05 11:03:56 +01005299 int i, err, idx, type_idx = 0;
5300 const char *prev_label = NULL;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005301
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005302 for (i = 0; i < cfg->num_inputs; i++) {
Takashi Iwai05f5f472009-08-25 13:10:18 +02005303 hda_nid_t pin;
Takashi Iwai10a20af2010-09-09 16:28:02 +02005304 const char *label;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005305
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005306 pin = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005307 if (!alc_is_input_pin(codec, pin))
5308 continue;
5309
David Henningsson5322bf22011-01-05 11:03:56 +01005310 label = hda_get_autocfg_input_label(codec, cfg, i);
5311 if (prev_label && !strcmp(label, prev_label))
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005312 type_idx++;
5313 else
5314 type_idx = 0;
David Henningsson5322bf22011-01-05 11:03:56 +01005315 prev_label = label;
5316
Takashi Iwai05f5f472009-08-25 13:10:18 +02005317 if (mixer) {
5318 idx = get_connection_index(codec, mixer, pin);
5319 if (idx >= 0) {
5320 err = new_analog_input(spec, pin,
Takashi Iwai10a20af2010-09-09 16:28:02 +02005321 label, type_idx,
5322 idx, mixer);
Takashi Iwai05f5f472009-08-25 13:10:18 +02005323 if (err < 0)
5324 return err;
5325 }
5326 }
5327
5328 if (!cap1)
5329 continue;
5330 idx = get_connection_index(codec, cap1, pin);
5331 if (idx < 0 && cap2)
5332 idx = get_connection_index(codec, cap2, pin);
Takashi Iwai10a20af2010-09-09 16:28:02 +02005333 if (idx >= 0)
5334 snd_hda_add_imux_item(imux, label, idx, NULL);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005335 }
5336 return 0;
5337}
5338
Takashi Iwai05f5f472009-08-25 13:10:18 +02005339static int alc880_auto_create_input_ctls(struct hda_codec *codec,
5340 const struct auto_pin_cfg *cfg)
5341{
5342 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x08, 0x09);
5343}
5344
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005345static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
5346 unsigned int pin_type)
5347{
5348 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5349 pin_type);
5350 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01005351 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
5352 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005353}
5354
Kailang Yangdf694da2005-12-05 19:42:22 +01005355static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
5356 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005357 int dac_idx)
5358{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005359 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005360 /* need the manual connection? */
5361 if (alc880_is_multi_pin(nid)) {
5362 struct alc_spec *spec = codec->spec;
5363 int idx = alc880_multi_pin_idx(nid);
5364 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
5365 AC_VERB_SET_CONNECT_SEL,
5366 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
5367 }
5368}
5369
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005370static int get_pin_type(int line_out_type)
5371{
5372 if (line_out_type == AUTO_PIN_HP_OUT)
5373 return PIN_HP;
5374 else
5375 return PIN_OUT;
5376}
5377
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005378static void alc880_auto_init_multi_out(struct hda_codec *codec)
5379{
5380 struct alc_spec *spec = codec->spec;
5381 int i;
Kailang Yangea1fb292008-08-26 12:58:38 +02005382
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005383 for (i = 0; i < spec->autocfg.line_outs; i++) {
5384 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005385 int pin_type = get_pin_type(spec->autocfg.line_out_type);
5386 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005387 }
5388}
5389
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005390static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005391{
5392 struct alc_spec *spec = codec->spec;
5393 hda_nid_t pin;
5394
Takashi Iwai82bc9552006-03-21 11:24:42 +01005395 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005396 if (pin) /* connect to front */
5397 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005398 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005399 if (pin) /* connect to front */
5400 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
5401}
5402
5403static void alc880_auto_init_analog_input(struct hda_codec *codec)
5404{
5405 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005406 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005407 int i;
5408
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005409 for (i = 0; i < cfg->num_inputs; i++) {
5410 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005411 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai30ea0982010-09-16 18:47:56 +02005412 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwaie82c0252009-03-23 15:17:38 +01005413 if (nid != ALC880_PIN_CD_NID &&
5414 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005415 snd_hda_codec_write(codec, nid, 0,
5416 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005417 AMP_OUT_MUTE);
5418 }
5419 }
5420}
5421
Takashi Iwai7f311a42010-04-09 17:32:23 +02005422static void alc880_auto_init_input_src(struct hda_codec *codec)
5423{
5424 struct alc_spec *spec = codec->spec;
5425 int c;
5426
5427 for (c = 0; c < spec->num_adc_nids; c++) {
5428 unsigned int mux_idx;
5429 const struct hda_input_mux *imux;
5430 mux_idx = c >= spec->num_mux_defs ? 0 : c;
5431 imux = &spec->input_mux[mux_idx];
5432 if (!imux->num_items && mux_idx > 0)
5433 imux = &spec->input_mux[0];
5434 if (imux)
5435 snd_hda_codec_write(codec, spec->adc_nids[c], 0,
5436 AC_VERB_SET_CONNECT_SEL,
5437 imux->items[0].index);
5438 }
5439}
5440
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005441/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005442/* return 1 if successful, 0 if the proper config is not found,
5443 * or a negative error code
5444 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005445static int alc880_parse_auto_config(struct hda_codec *codec)
5446{
5447 struct alc_spec *spec = codec->spec;
Takashi Iwai757899a2010-07-30 10:48:14 +02005448 int err;
Kailang Yangdf694da2005-12-05 19:42:22 +01005449 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005450
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005451 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
5452 alc880_ignore);
5453 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005454 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005455 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005456 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01005457
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005458 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
5459 if (err < 0)
5460 return err;
5461 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
5462 if (err < 0)
5463 return err;
5464 err = alc880_auto_create_extra_out(spec,
5465 spec->autocfg.speaker_pins[0],
5466 "Speaker");
5467 if (err < 0)
5468 return err;
5469 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
5470 "Headphone");
5471 if (err < 0)
5472 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005473 err = alc880_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005474 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005475 return err;
5476
5477 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
5478
Takashi Iwai757899a2010-07-30 10:48:14 +02005479 alc_auto_parse_digital(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005480
Takashi Iwai603c4012008-07-30 15:01:44 +02005481 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01005482 add_mixer(spec, spec->kctls.list);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005483
Takashi Iwaid88897e2008-10-31 15:01:37 +01005484 add_verb(spec, alc880_volume_init_verbs);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005485
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005486 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005487 spec->input_mux = &spec->private_imux[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005488
Kailang Yang6227cdc2010-02-25 08:36:52 +01005489 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02005490
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005491 return 1;
5492}
5493
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005494/* additional initialization for auto-configuration model */
5495static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005496{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005497 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005498 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005499 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005500 alc880_auto_init_analog_input(codec);
Takashi Iwai7f311a42010-04-09 17:32:23 +02005501 alc880_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +02005502 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005503 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02005504 alc_inithook(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005505}
5506
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005507/* check the ADC/MUX contains all input pins; some ADC/MUX contains only
5508 * one of two digital mic pins, e.g. on ALC272
5509 */
5510static void fixup_automic_adc(struct hda_codec *codec)
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005511{
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005512 struct alc_spec *spec = codec->spec;
5513 int i;
5514
5515 for (i = 0; i < spec->num_adc_nids; i++) {
5516 hda_nid_t cap = spec->capsrc_nids ?
5517 spec->capsrc_nids[i] : spec->adc_nids[i];
5518 int iidx, eidx;
5519
5520 iidx = get_connection_index(codec, cap, spec->int_mic.pin);
5521 if (iidx < 0)
5522 continue;
5523 eidx = get_connection_index(codec, cap, spec->ext_mic.pin);
5524 if (eidx < 0)
5525 continue;
5526 spec->int_mic.mux_idx = iidx;
5527 spec->ext_mic.mux_idx = eidx;
5528 if (spec->capsrc_nids)
5529 spec->capsrc_nids += i;
5530 spec->adc_nids += i;
5531 spec->num_adc_nids = 1;
5532 return;
5533 }
5534 snd_printd(KERN_INFO "hda_codec: %s: "
5535 "No ADC/MUX containing both 0x%x and 0x%x pins\n",
5536 codec->chip_name, spec->int_mic.pin, spec->ext_mic.pin);
5537 spec->auto_mic = 0; /* disable auto-mic to be sure */
5538}
5539
Takashi Iwai748cce42010-08-04 07:37:39 +02005540/* select or unmute the given capsrc route */
5541static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap,
5542 int idx)
5543{
5544 if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
5545 snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
5546 HDA_AMP_MUTE, 0);
5547 } else {
5548 snd_hda_codec_write_cache(codec, cap, 0,
5549 AC_VERB_SET_CONNECT_SEL, idx);
5550 }
5551}
5552
Takashi Iwai840b64c2010-07-13 22:49:01 +02005553/* set the default connection to that pin */
5554static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
5555{
5556 struct alc_spec *spec = codec->spec;
5557 int i;
5558
5559 for (i = 0; i < spec->num_adc_nids; i++) {
5560 hda_nid_t cap = spec->capsrc_nids ?
5561 spec->capsrc_nids[i] : spec->adc_nids[i];
5562 int idx;
5563
5564 idx = get_connection_index(codec, cap, pin);
5565 if (idx < 0)
5566 continue;
Takashi Iwai748cce42010-08-04 07:37:39 +02005567 select_or_unmute_capsrc(codec, cap, idx);
Takashi Iwai840b64c2010-07-13 22:49:01 +02005568 return i; /* return the found index */
5569 }
5570 return -1; /* not found */
5571}
5572
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005573/* choose the ADC/MUX containing the input pin and initialize the setup */
5574static void fixup_single_adc(struct hda_codec *codec)
5575{
5576 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005577 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005578 int i;
5579
5580 /* search for the input pin; there must be only one */
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005581 if (cfg->num_inputs != 1)
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005582 return;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005583 i = init_capsrc_for_pin(codec, cfg->inputs[0].pin);
Takashi Iwai840b64c2010-07-13 22:49:01 +02005584 if (i >= 0) {
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005585 /* use only this ADC */
5586 if (spec->capsrc_nids)
5587 spec->capsrc_nids += i;
5588 spec->adc_nids += i;
5589 spec->num_adc_nids = 1;
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005590 }
5591}
5592
Takashi Iwai840b64c2010-07-13 22:49:01 +02005593/* initialize dual adcs */
5594static void fixup_dual_adc_switch(struct hda_codec *codec)
5595{
5596 struct alc_spec *spec = codec->spec;
5597 init_capsrc_for_pin(codec, spec->ext_mic.pin);
5598 init_capsrc_for_pin(codec, spec->int_mic.pin);
5599}
5600
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005601static void set_capture_mixer(struct hda_codec *codec)
5602{
5603 struct alc_spec *spec = codec->spec;
Takashi Iwaia23b6882009-03-23 15:21:36 +01005604 static struct snd_kcontrol_new *caps[2][3] = {
5605 { alc_capture_mixer_nosrc1,
5606 alc_capture_mixer_nosrc2,
5607 alc_capture_mixer_nosrc3 },
5608 { alc_capture_mixer1,
5609 alc_capture_mixer2,
5610 alc_capture_mixer3 },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005611 };
Takashi Iwaia23b6882009-03-23 15:21:36 +01005612 if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005613 int mux = 0;
Takashi Iwai840b64c2010-07-13 22:49:01 +02005614 int num_adcs = spec->num_adc_nids;
5615 if (spec->dual_adc_switch)
5616 fixup_dual_adc_switch(codec);
5617 else if (spec->auto_mic)
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005618 fixup_automic_adc(codec);
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005619 else if (spec->input_mux) {
5620 if (spec->input_mux->num_items > 1)
5621 mux = 1;
5622 else if (spec->input_mux->num_items == 1)
5623 fixup_single_adc(codec);
5624 }
Takashi Iwai840b64c2010-07-13 22:49:01 +02005625 if (spec->dual_adc_switch)
5626 num_adcs = 1;
5627 spec->cap_mixer = caps[mux][num_adcs - 1];
Takashi Iwaia23b6882009-03-23 15:21:36 +01005628 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005629}
5630
Takashi Iwai66946352010-03-29 17:21:45 +02005631/* fill adc_nids (and capsrc_nids) containing all active input pins */
5632static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids,
5633 int num_nids)
5634{
5635 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005636 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai66946352010-03-29 17:21:45 +02005637 int n;
5638 hda_nid_t fallback_adc = 0, fallback_cap = 0;
5639
5640 for (n = 0; n < num_nids; n++) {
5641 hda_nid_t adc, cap;
5642 hda_nid_t conn[HDA_MAX_NUM_INPUTS];
5643 int nconns, i, j;
5644
5645 adc = nids[n];
5646 if (get_wcaps_type(get_wcaps(codec, adc)) != AC_WID_AUD_IN)
5647 continue;
5648 cap = adc;
5649 nconns = snd_hda_get_connections(codec, cap, conn,
5650 ARRAY_SIZE(conn));
5651 if (nconns == 1) {
5652 cap = conn[0];
5653 nconns = snd_hda_get_connections(codec, cap, conn,
5654 ARRAY_SIZE(conn));
5655 }
5656 if (nconns <= 0)
5657 continue;
5658 if (!fallback_adc) {
5659 fallback_adc = adc;
5660 fallback_cap = cap;
5661 }
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005662 for (i = 0; i < cfg->num_inputs; i++) {
5663 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai66946352010-03-29 17:21:45 +02005664 for (j = 0; j < nconns; j++) {
5665 if (conn[j] == nid)
5666 break;
5667 }
5668 if (j >= nconns)
5669 break;
5670 }
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005671 if (i >= cfg->num_inputs) {
Takashi Iwai66946352010-03-29 17:21:45 +02005672 int num_adcs = spec->num_adc_nids;
5673 spec->private_adc_nids[num_adcs] = adc;
5674 spec->private_capsrc_nids[num_adcs] = cap;
5675 spec->num_adc_nids++;
5676 spec->adc_nids = spec->private_adc_nids;
5677 if (adc != cap)
5678 spec->capsrc_nids = spec->private_capsrc_nids;
5679 }
5680 }
5681 if (!spec->num_adc_nids) {
5682 printk(KERN_WARNING "hda_codec: %s: no valid ADC found;"
Takashi Iwai1f85d722010-03-30 07:48:05 +02005683 " using fallback 0x%x\n",
5684 codec->chip_name, fallback_adc);
Takashi Iwai66946352010-03-29 17:21:45 +02005685 spec->private_adc_nids[0] = fallback_adc;
5686 spec->adc_nids = spec->private_adc_nids;
5687 if (fallback_adc != fallback_cap) {
5688 spec->private_capsrc_nids[0] = fallback_cap;
5689 spec->capsrc_nids = spec->private_adc_nids;
5690 }
5691 }
5692}
5693
Takashi Iwai67d634c2009-11-16 15:35:59 +01005694#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005695#define set_beep_amp(spec, nid, idx, dir) \
5696 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005697
5698static struct snd_pci_quirk beep_white_list[] = {
5699 SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
Takashi Iwai080dc7b2010-09-08 08:38:41 +02005700 SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
Takashi Iwaie096c8e2010-08-03 17:20:35 +02005701 SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005702 {}
5703};
5704
5705static inline int has_cdefine_beep(struct hda_codec *codec)
5706{
5707 struct alc_spec *spec = codec->spec;
5708 const struct snd_pci_quirk *q;
5709 q = snd_pci_quirk_lookup(codec->bus->pci, beep_white_list);
5710 if (q)
5711 return q->value;
5712 return spec->cdefine.enable_pcbeep;
5713}
Takashi Iwai67d634c2009-11-16 15:35:59 +01005714#else
5715#define set_beep_amp(spec, nid, idx, dir) /* NOP */
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005716#define has_cdefine_beep(codec) 0
Takashi Iwai67d634c2009-11-16 15:35:59 +01005717#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005718
5719/*
5720 * OK, here we have finally the patch for ALC880
5721 */
5722
Linus Torvalds1da177e2005-04-16 15:20:36 -07005723static int patch_alc880(struct hda_codec *codec)
5724{
5725 struct alc_spec *spec;
5726 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01005727 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005728
Takashi Iwaie560d8d2005-09-09 14:21:46 +02005729 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005730 if (spec == NULL)
5731 return -ENOMEM;
5732
5733 codec->spec = spec;
5734
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005735 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
5736 alc880_models,
5737 alc880_cfg_tbl);
5738 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02005739 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
5740 codec->chip_name);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005741 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005742 }
5743
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005744 if (board_config == ALC880_AUTO) {
5745 /* automatic parse from the BIOS config */
5746 err = alc880_parse_auto_config(codec);
5747 if (err < 0) {
5748 alc_free(codec);
5749 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005750 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005751 printk(KERN_INFO
5752 "hda_codec: Cannot set up configuration "
5753 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005754 board_config = ALC880_3ST;
5755 }
5756 }
5757
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09005758 err = snd_hda_attach_beep_device(codec, 0x1);
5759 if (err < 0) {
5760 alc_free(codec);
5761 return err;
5762 }
5763
Kailang Yangdf694da2005-12-05 19:42:22 +01005764 if (board_config != ALC880_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02005765 setup_preset(codec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005766
Linus Torvalds1da177e2005-04-16 15:20:36 -07005767 spec->stream_analog_playback = &alc880_pcm_analog_playback;
5768 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01005769 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005770
Linus Torvalds1da177e2005-04-16 15:20:36 -07005771 spec->stream_digital_playback = &alc880_pcm_digital_playback;
5772 spec->stream_digital_capture = &alc880_pcm_digital_capture;
5773
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005774 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005775 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01005776 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005777 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +02005778 wcap = get_wcaps_type(wcap);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005779 if (wcap != AC_WID_AUD_IN) {
5780 spec->adc_nids = alc880_adc_nids_alt;
5781 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005782 } else {
5783 spec->adc_nids = alc880_adc_nids;
5784 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005785 }
5786 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005787 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005788 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005789
Takashi Iwai2134ea42008-01-10 16:53:55 +01005790 spec->vmaster_nid = 0x0c;
5791
Linus Torvalds1da177e2005-04-16 15:20:36 -07005792 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005793 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005794 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02005795#ifdef CONFIG_SND_HDA_POWER_SAVE
5796 if (!spec->loopback.amplist)
5797 spec->loopback.amplist = alc880_loopbacks;
5798#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005799
5800 return 0;
5801}
5802
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005803
Linus Torvalds1da177e2005-04-16 15:20:36 -07005804/*
5805 * ALC260 support
5806 */
5807
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005808static hda_nid_t alc260_dac_nids[1] = {
5809 /* front */
5810 0x02,
5811};
5812
5813static hda_nid_t alc260_adc_nids[1] = {
5814 /* ADC0 */
5815 0x04,
5816};
5817
Kailang Yangdf694da2005-12-05 19:42:22 +01005818static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005819 /* ADC1 */
5820 0x05,
5821};
5822
Jonathan Woithed57fdac2006-02-28 11:38:35 +01005823/* NIDs used when simultaneous access to both ADCs makes sense. Note that
5824 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
5825 */
5826static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005827 /* ADC0, ADC1 */
5828 0x04, 0x05
5829};
5830
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005831#define ALC260_DIGOUT_NID 0x03
5832#define ALC260_DIGIN_NID 0x06
5833
5834static struct hda_input_mux alc260_capture_source = {
5835 .num_items = 4,
5836 .items = {
5837 { "Mic", 0x0 },
5838 { "Front Mic", 0x1 },
5839 { "Line", 0x2 },
5840 { "CD", 0x4 },
5841 },
5842};
5843
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01005844/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005845 * headphone jack and the internal CD lines since these are the only pins at
5846 * which audio can appear. For flexibility, also allow the option of
5847 * recording the mixer output on the second ADC (ADC0 doesn't have a
5848 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005849 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005850static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
5851 {
5852 .num_items = 3,
5853 .items = {
5854 { "Mic/Line", 0x0 },
5855 { "CD", 0x4 },
5856 { "Headphone", 0x2 },
5857 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005858 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005859 {
5860 .num_items = 4,
5861 .items = {
5862 { "Mic/Line", 0x0 },
5863 { "CD", 0x4 },
5864 { "Headphone", 0x2 },
5865 { "Mixer", 0x5 },
5866 },
5867 },
5868
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005869};
5870
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005871/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
5872 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005873 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005874static struct hda_input_mux alc260_acer_capture_sources[2] = {
5875 {
5876 .num_items = 4,
5877 .items = {
5878 { "Mic", 0x0 },
5879 { "Line", 0x2 },
5880 { "CD", 0x4 },
5881 { "Headphone", 0x5 },
5882 },
5883 },
5884 {
5885 .num_items = 5,
5886 .items = {
5887 { "Mic", 0x0 },
5888 { "Line", 0x2 },
5889 { "CD", 0x4 },
5890 { "Headphone", 0x6 },
5891 { "Mixer", 0x5 },
5892 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005893 },
5894};
Michael Schwingencc959482009-02-22 18:58:45 +01005895
5896/* Maxdata Favorit 100XS */
5897static struct hda_input_mux alc260_favorit100_capture_sources[2] = {
5898 {
5899 .num_items = 2,
5900 .items = {
5901 { "Line/Mic", 0x0 },
5902 { "CD", 0x4 },
5903 },
5904 },
5905 {
5906 .num_items = 3,
5907 .items = {
5908 { "Line/Mic", 0x0 },
5909 { "CD", 0x4 },
5910 { "Mixer", 0x5 },
5911 },
5912 },
5913};
5914
Linus Torvalds1da177e2005-04-16 15:20:36 -07005915/*
5916 * This is just place-holder, so there's something for alc_build_pcms to look
5917 * at when it calculates the maximum number of channels. ALC260 has no mixer
5918 * element which allows changing the channel mode, so the verb list is
5919 * never used.
5920 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01005921static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005922 { 2, NULL },
5923};
5924
Kailang Yangdf694da2005-12-05 19:42:22 +01005925
5926/* Mixer combinations
5927 *
5928 * basic: base_output + input + pc_beep + capture
5929 * HP: base_output + input + capture_alt
5930 * HP_3013: hp_3013 + input + capture
5931 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005932 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01005933 */
5934
5935static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02005936 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005937 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01005938 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5939 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
5940 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5941 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5942 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005943};
Kailang Yangdf694da2005-12-05 19:42:22 +01005944
5945static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005946 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5947 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5948 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5949 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5950 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5951 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5952 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
5953 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005954 { } /* end */
5955};
5956
Takashi Iwaibec15c32008-01-28 18:16:30 +01005957/* update HP, line and mono out pins according to the master switch */
5958static void alc260_hp_master_update(struct hda_codec *codec,
5959 hda_nid_t hp, hda_nid_t line,
5960 hda_nid_t mono)
5961{
5962 struct alc_spec *spec = codec->spec;
5963 unsigned int val = spec->master_sw ? PIN_HP : 0;
5964 /* change HP and line-out pins */
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005965 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005966 val);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005967 snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005968 val);
5969 /* mono (speaker) depending on the HP jack sense */
5970 val = (val && !spec->jack_present) ? PIN_OUT : 0;
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005971 snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005972 val);
5973}
5974
5975static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
5976 struct snd_ctl_elem_value *ucontrol)
5977{
5978 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5979 struct alc_spec *spec = codec->spec;
5980 *ucontrol->value.integer.value = spec->master_sw;
5981 return 0;
5982}
5983
5984static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
5985 struct snd_ctl_elem_value *ucontrol)
5986{
5987 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5988 struct alc_spec *spec = codec->spec;
5989 int val = !!*ucontrol->value.integer.value;
5990 hda_nid_t hp, line, mono;
5991
5992 if (val == spec->master_sw)
5993 return 0;
5994 spec->master_sw = val;
5995 hp = (kcontrol->private_value >> 16) & 0xff;
5996 line = (kcontrol->private_value >> 8) & 0xff;
5997 mono = kcontrol->private_value & 0xff;
5998 alc260_hp_master_update(codec, hp, line, mono);
5999 return 1;
6000}
6001
6002static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
6003 {
6004 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6005 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01006006 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006007 .info = snd_ctl_boolean_mono_info,
6008 .get = alc260_hp_master_sw_get,
6009 .put = alc260_hp_master_sw_put,
6010 .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
6011 },
6012 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6013 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
6014 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6015 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
6016 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
6017 HDA_OUTPUT),
6018 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
6019 { } /* end */
6020};
6021
6022static struct hda_verb alc260_hp_unsol_verbs[] = {
6023 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6024 {},
6025};
6026
6027static void alc260_hp_automute(struct hda_codec *codec)
6028{
6029 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006030
Wu Fengguang864f92b2009-11-18 12:38:02 +08006031 spec->jack_present = snd_hda_jack_detect(codec, 0x10);
Takashi Iwaibec15c32008-01-28 18:16:30 +01006032 alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
6033}
6034
6035static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
6036{
6037 if ((res >> 26) == ALC880_HP_EVENT)
6038 alc260_hp_automute(codec);
6039}
6040
Kailang Yangdf694da2005-12-05 19:42:22 +01006041static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006042 {
6043 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6044 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01006045 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006046 .info = snd_ctl_boolean_mono_info,
6047 .get = alc260_hp_master_sw_get,
6048 .put = alc260_hp_master_sw_put,
Takashi Iwai30cde0a2008-11-07 14:49:28 +01006049 .private_value = (0x15 << 16) | (0x10 << 8) | 0x11
Takashi Iwaibec15c32008-01-28 18:16:30 +01006050 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006051 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6052 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
6053 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
6054 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
6055 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6056 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01006057 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
6058 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02006059 { } /* end */
6060};
6061
Kailang Yang3f878302008-08-26 13:02:23 +02006062static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
6063 .ops = &snd_hda_bind_vol,
6064 .values = {
6065 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
6066 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
6067 HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
6068 0
6069 },
6070};
6071
6072static struct hda_bind_ctls alc260_dc7600_bind_switch = {
6073 .ops = &snd_hda_bind_sw,
6074 .values = {
6075 HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
6076 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
6077 0
6078 },
6079};
6080
6081static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
6082 HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
6083 HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
6084 HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
6085 HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
6086 { } /* end */
6087};
6088
Takashi Iwaibec15c32008-01-28 18:16:30 +01006089static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
6090 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6091 {},
6092};
6093
6094static void alc260_hp_3013_automute(struct hda_codec *codec)
6095{
6096 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006097
Wu Fengguang864f92b2009-11-18 12:38:02 +08006098 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01006099 alc260_hp_master_update(codec, 0x15, 0x10, 0x11);
Takashi Iwaibec15c32008-01-28 18:16:30 +01006100}
6101
6102static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
6103 unsigned int res)
6104{
6105 if ((res >> 26) == ALC880_HP_EVENT)
6106 alc260_hp_3013_automute(codec);
6107}
6108
Kailang Yang3f878302008-08-26 13:02:23 +02006109static void alc260_hp_3012_automute(struct hda_codec *codec)
6110{
Wu Fengguang864f92b2009-11-18 12:38:02 +08006111 unsigned int bits = snd_hda_jack_detect(codec, 0x10) ? 0 : PIN_OUT;
Kailang Yang3f878302008-08-26 13:02:23 +02006112
Kailang Yang3f878302008-08-26 13:02:23 +02006113 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
6114 bits);
6115 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
6116 bits);
6117 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
6118 bits);
6119}
6120
6121static void alc260_hp_3012_unsol_event(struct hda_codec *codec,
6122 unsigned int res)
6123{
6124 if ((res >> 26) == ALC880_HP_EVENT)
6125 alc260_hp_3012_automute(codec);
6126}
6127
6128/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006129 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
6130 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01006131static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006132 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006133 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006134 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006135 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6136 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
6137 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
6138 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006139 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01006140 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6141 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01006142 { } /* end */
6143};
6144
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006145/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
6146 * versions of the ALC260 don't act on requests to enable mic bias from NID
6147 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
6148 * datasheet doesn't mention this restriction. At this stage it's not clear
6149 * whether this behaviour is intentional or is a hardware bug in chip
6150 * revisions available in early 2006. Therefore for now allow the
6151 * "Headphone Jack Mode" control to span all choices, but if it turns out
6152 * that the lack of mic bias for this NID is intentional we could change the
6153 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
6154 *
6155 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
6156 * don't appear to make the mic bias available from the "line" jack, even
6157 * though the NID used for this jack (0x14) can supply it. The theory is
6158 * that perhaps Acer have included blocking capacitors between the ALC260
6159 * and the output jack. If this turns out to be the case for all such
6160 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
6161 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01006162 *
6163 * The C20x Tablet series have a mono internal speaker which is controlled
6164 * via the chip's Mono sum widget and pin complex, so include the necessary
6165 * controls for such models. On models without a "mono speaker" the control
6166 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006167 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006168static struct snd_kcontrol_new alc260_acer_mixer[] = {
6169 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6170 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006171 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01006172 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01006173 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01006174 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01006175 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006176 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6177 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
6178 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6179 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6180 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6181 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6182 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6183 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006184 { } /* end */
6185};
6186
Michael Schwingencc959482009-02-22 18:58:45 +01006187/* Maxdata Favorit 100XS: one output and one input (0x12) jack
6188 */
6189static struct snd_kcontrol_new alc260_favorit100_mixer[] = {
6190 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6191 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
6192 ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
6193 HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6194 HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6195 ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6196 { } /* end */
6197};
6198
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006199/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
6200 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
6201 */
6202static struct snd_kcontrol_new alc260_will_mixer[] = {
6203 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6204 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
6205 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6206 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6207 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6208 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6209 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6210 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
6211 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6212 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006213 { } /* end */
6214};
6215
6216/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
6217 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
6218 */
6219static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
6220 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6221 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
6222 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6223 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6224 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6225 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
6226 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
6227 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6228 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6229 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
6230 { } /* end */
6231};
6232
Kailang Yangdf694da2005-12-05 19:42:22 +01006233/*
6234 * initialization verbs
6235 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006236static struct hda_verb alc260_init_verbs[] = {
6237 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006238 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006239 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006240 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006241 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006242 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006243 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006244 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006245 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02006246 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006247 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01006248 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006249 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02006250 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006251 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02006252 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006253 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02006254 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6255 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02006256 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006257 /* set connection select to line in (default select for this ADC) */
6258 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02006259 /* mute capture amp left and right */
6260 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6261 /* set connection select to line in (default select for this ADC) */
6262 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02006263 /* set vol=0 Line-Out mixer amp left and right */
6264 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6265 /* unmute pin widget amp left and right (no gain on this amp) */
6266 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6267 /* set vol=0 HP mixer amp left and right */
6268 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6269 /* unmute pin widget amp left and right (no gain on this amp) */
6270 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6271 /* set vol=0 Mono mixer amp left and right */
6272 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6273 /* unmute pin widget amp left and right (no gain on this amp) */
6274 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6275 /* unmute LINE-2 out pin */
6276 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006277 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6278 * Line In 2 = 0x03
6279 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006280 /* mute analog inputs */
6281 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6282 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6283 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6284 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6285 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006286 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02006287 /* mute Front out path */
6288 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6289 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6290 /* mute Headphone out path */
6291 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6292 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6293 /* mute Mono out path */
6294 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6295 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006296 { }
6297};
6298
Takashi Iwai474167d2006-05-17 17:17:43 +02006299#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01006300static struct hda_verb alc260_hp_init_verbs[] = {
6301 /* Headphone and output */
6302 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
6303 /* mono output */
6304 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6305 /* Mic1 (rear panel) pin widget for input and vref at 80% */
6306 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6307 /* Mic2 (front panel) pin widget for input and vref at 80% */
6308 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6309 /* Line In pin widget for input */
6310 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6311 /* Line-2 pin widget for output */
6312 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6313 /* CD pin widget for input */
6314 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6315 /* unmute amp left and right */
6316 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
6317 /* set connection select to line in (default select for this ADC) */
6318 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
6319 /* unmute Line-Out mixer amp left and right (volume = 0) */
6320 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6321 /* mute pin widget amp left and right (no gain on this amp) */
6322 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
6323 /* unmute HP mixer amp left and right (volume = 0) */
6324 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6325 /* mute pin widget amp left and right (no gain on this amp) */
6326 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006327 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6328 * Line In 2 = 0x03
6329 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006330 /* mute analog inputs */
6331 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6332 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6333 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6334 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6335 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006336 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
6337 /* Unmute Front out path */
6338 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6339 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6340 /* Unmute Headphone out path */
6341 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6342 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6343 /* Unmute Mono out path */
6344 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6345 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6346 { }
6347};
Takashi Iwai474167d2006-05-17 17:17:43 +02006348#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01006349
6350static struct hda_verb alc260_hp_3013_init_verbs[] = {
6351 /* Line out and output */
6352 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6353 /* mono output */
6354 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6355 /* Mic1 (rear panel) pin widget for input and vref at 80% */
6356 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6357 /* Mic2 (front panel) pin widget for input and vref at 80% */
6358 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6359 /* Line In pin widget for input */
6360 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6361 /* Headphone pin widget for output */
6362 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
6363 /* CD pin widget for input */
6364 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6365 /* unmute amp left and right */
6366 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
6367 /* set connection select to line in (default select for this ADC) */
6368 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
6369 /* unmute Line-Out mixer amp left and right (volume = 0) */
6370 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6371 /* mute pin widget amp left and right (no gain on this amp) */
6372 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
6373 /* unmute HP mixer amp left and right (volume = 0) */
6374 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6375 /* mute pin widget amp left and right (no gain on this amp) */
6376 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006377 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6378 * Line In 2 = 0x03
6379 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006380 /* mute analog inputs */
6381 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6382 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6383 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6384 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6385 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006386 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
6387 /* Unmute Front out path */
6388 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6389 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6390 /* Unmute Headphone out path */
6391 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6392 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6393 /* Unmute Mono out path */
6394 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6395 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6396 { }
6397};
6398
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006399/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006400 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
6401 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006402 */
6403static struct hda_verb alc260_fujitsu_init_verbs[] = {
6404 /* Disable all GPIOs */
6405 {0x01, AC_VERB_SET_GPIO_MASK, 0},
6406 /* Internal speaker is connected to headphone pin */
6407 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6408 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
6409 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006410 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
6411 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6412 /* Ensure all other unused pins are disabled and muted. */
6413 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6414 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006415 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006416 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006417 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006418 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6419 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6420 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006421
Jonathan Woithef7ace402006-02-28 11:46:14 +01006422 /* Disable digital (SPDIF) pins */
6423 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6424 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006425
Kailang Yangea1fb292008-08-26 12:58:38 +02006426 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
Jonathan Woithef7ace402006-02-28 11:46:14 +01006427 * when acting as an output.
6428 */
6429 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6430
6431 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01006432 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6433 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6434 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6435 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6436 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6437 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6438 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6439 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6440 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006441
Jonathan Woithef7ace402006-02-28 11:46:14 +01006442 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
6443 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6444 /* Unmute Line1 pin widget output buffer since it starts as an output.
6445 * If the pin mode is changed by the user the pin mode control will
6446 * take care of enabling the pin's input/output buffers as needed.
6447 * Therefore there's no need to enable the input buffer at this
6448 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006449 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01006450 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +02006451 /* Unmute input buffer of pin widget used for Line-in (no equiv
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006452 * mixer ctrl)
6453 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01006454 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006455
Jonathan Woithef7ace402006-02-28 11:46:14 +01006456 /* Mute capture amp left and right */
6457 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006458 /* Set ADC connection select to match default mixer setting - line
Jonathan Woithef7ace402006-02-28 11:46:14 +01006459 * in (on mic1 pin)
6460 */
6461 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006462
Jonathan Woithef7ace402006-02-28 11:46:14 +01006463 /* Do the same for the second ADC: mute capture input amp and
6464 * set ADC connection to line in (on mic1 pin)
6465 */
6466 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6467 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006468
Jonathan Woithef7ace402006-02-28 11:46:14 +01006469 /* Mute all inputs to mixer widget (even unconnected ones) */
6470 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6471 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6472 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6473 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6474 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6475 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6476 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6477 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01006478
6479 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006480};
6481
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006482/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
6483 * similar laptops (adapted from Fujitsu init verbs).
6484 */
6485static struct hda_verb alc260_acer_init_verbs[] = {
6486 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
6487 * the headphone jack. Turn this on and rely on the standard mute
6488 * methods whenever the user wants to turn these outputs off.
6489 */
6490 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6491 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6492 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
6493 /* Internal speaker/Headphone jack is connected to Line-out pin */
6494 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6495 /* Internal microphone/Mic jack is connected to Mic1 pin */
6496 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
6497 /* Line In jack is connected to Line1 pin */
6498 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01006499 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
6500 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006501 /* Ensure all other unused pins are disabled and muted. */
6502 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6503 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006504 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6505 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6506 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6507 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6508 /* Disable digital (SPDIF) pins */
6509 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6510 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6511
Kailang Yangea1fb292008-08-26 12:58:38 +02006512 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006513 * bus when acting as outputs.
6514 */
6515 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6516 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6517
6518 /* Start with output sum widgets muted and their output gains at min */
6519 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6520 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6521 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6522 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6523 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6524 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6525 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6526 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6527 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6528
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006529 /* Unmute Line-out pin widget amp left and right
6530 * (no equiv mixer ctrl)
6531 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006532 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01006533 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
6534 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006535 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
6536 * inputs. If the pin mode is changed by the user the pin mode control
6537 * will take care of enabling the pin's input/output buffers as needed.
6538 * Therefore there's no need to enable the input buffer at this
6539 * stage.
6540 */
6541 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6542 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6543
6544 /* Mute capture amp left and right */
6545 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6546 /* Set ADC connection select to match default mixer setting - mic
6547 * (on mic1 pin)
6548 */
6549 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6550
6551 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006552 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006553 */
6554 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006555 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006556
6557 /* Mute all inputs to mixer widget (even unconnected ones) */
6558 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6559 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6560 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6561 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6562 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6563 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6564 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6565 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6566
6567 { }
6568};
6569
Michael Schwingencc959482009-02-22 18:58:45 +01006570/* Initialisation sequence for Maxdata Favorit 100XS
6571 * (adapted from Acer init verbs).
6572 */
6573static struct hda_verb alc260_favorit100_init_verbs[] = {
6574 /* GPIO 0 enables the output jack.
6575 * Turn this on and rely on the standard mute
6576 * methods whenever the user wants to turn these outputs off.
6577 */
6578 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6579 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6580 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
6581 /* Line/Mic input jack is connected to Mic1 pin */
6582 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
6583 /* Ensure all other unused pins are disabled and muted. */
6584 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6585 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6586 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6587 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6588 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6589 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6590 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6591 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6592 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6593 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6594 /* Disable digital (SPDIF) pins */
6595 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6596 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6597
6598 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
6599 * bus when acting as outputs.
6600 */
6601 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6602 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6603
6604 /* Start with output sum widgets muted and their output gains at min */
6605 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6606 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6607 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6608 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6609 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6610 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6611 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6612 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6613 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6614
6615 /* Unmute Line-out pin widget amp left and right
6616 * (no equiv mixer ctrl)
6617 */
6618 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6619 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
6620 * inputs. If the pin mode is changed by the user the pin mode control
6621 * will take care of enabling the pin's input/output buffers as needed.
6622 * Therefore there's no need to enable the input buffer at this
6623 * stage.
6624 */
6625 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6626
6627 /* Mute capture amp left and right */
6628 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6629 /* Set ADC connection select to match default mixer setting - mic
6630 * (on mic1 pin)
6631 */
6632 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6633
6634 /* Do similar with the second ADC: mute capture input amp and
6635 * set ADC connection to mic to match ALSA's default state.
6636 */
6637 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6638 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6639
6640 /* Mute all inputs to mixer widget (even unconnected ones) */
6641 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6642 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6643 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6644 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6645 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6646 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6647 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6648 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6649
6650 { }
6651};
6652
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006653static struct hda_verb alc260_will_verbs[] = {
6654 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6655 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
6656 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
6657 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
6658 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
6659 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
6660 {}
6661};
6662
6663static struct hda_verb alc260_replacer_672v_verbs[] = {
6664 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
6665 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
6666 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
6667
6668 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6669 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6670 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6671
6672 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6673 {}
6674};
6675
6676/* toggle speaker-output according to the hp-jack state */
6677static void alc260_replacer_672v_automute(struct hda_codec *codec)
6678{
6679 unsigned int present;
6680
6681 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
Wu Fengguang864f92b2009-11-18 12:38:02 +08006682 present = snd_hda_jack_detect(codec, 0x0f);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006683 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006684 snd_hda_codec_write_cache(codec, 0x01, 0,
6685 AC_VERB_SET_GPIO_DATA, 1);
6686 snd_hda_codec_write_cache(codec, 0x0f, 0,
6687 AC_VERB_SET_PIN_WIDGET_CONTROL,
6688 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006689 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006690 snd_hda_codec_write_cache(codec, 0x01, 0,
6691 AC_VERB_SET_GPIO_DATA, 0);
6692 snd_hda_codec_write_cache(codec, 0x0f, 0,
6693 AC_VERB_SET_PIN_WIDGET_CONTROL,
6694 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006695 }
6696}
6697
6698static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
6699 unsigned int res)
6700{
6701 if ((res >> 26) == ALC880_HP_EVENT)
6702 alc260_replacer_672v_automute(codec);
6703}
6704
Kailang Yang3f878302008-08-26 13:02:23 +02006705static struct hda_verb alc260_hp_dc7600_verbs[] = {
6706 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
6707 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
6708 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6709 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6710 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6711 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6712 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6713 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6714 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6715 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6716 {}
6717};
6718
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006719/* Test configuration for debugging, modelled after the ALC880 test
6720 * configuration.
6721 */
6722#ifdef CONFIG_SND_DEBUG
6723static hda_nid_t alc260_test_dac_nids[1] = {
6724 0x02,
6725};
6726static hda_nid_t alc260_test_adc_nids[2] = {
6727 0x04, 0x05,
6728};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006729/* For testing the ALC260, each input MUX needs its own definition since
Kailang Yangea1fb292008-08-26 12:58:38 +02006730 * the signal assignments are different. This assumes that the first ADC
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006731 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01006732 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006733static struct hda_input_mux alc260_test_capture_sources[2] = {
6734 {
6735 .num_items = 7,
6736 .items = {
6737 { "MIC1 pin", 0x0 },
6738 { "MIC2 pin", 0x1 },
6739 { "LINE1 pin", 0x2 },
6740 { "LINE2 pin", 0x3 },
6741 { "CD pin", 0x4 },
6742 { "LINE-OUT pin", 0x5 },
6743 { "HP-OUT pin", 0x6 },
6744 },
6745 },
6746 {
6747 .num_items = 8,
6748 .items = {
6749 { "MIC1 pin", 0x0 },
6750 { "MIC2 pin", 0x1 },
6751 { "LINE1 pin", 0x2 },
6752 { "LINE2 pin", 0x3 },
6753 { "CD pin", 0x4 },
6754 { "Mixer", 0x5 },
6755 { "LINE-OUT pin", 0x6 },
6756 { "HP-OUT pin", 0x7 },
6757 },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006758 },
6759};
6760static struct snd_kcontrol_new alc260_test_mixer[] = {
6761 /* Output driver widgets */
6762 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
6763 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
6764 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6765 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
6766 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6767 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
6768
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006769 /* Modes for retasking pin widgets
6770 * Note: the ALC260 doesn't seem to act on requests to enable mic
6771 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
6772 * mention this restriction. At this stage it's not clear whether
6773 * this behaviour is intentional or is a hardware bug in chip
6774 * revisions available at least up until early 2006. Therefore for
6775 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
6776 * choices, but if it turns out that the lack of mic bias for these
6777 * NIDs is intentional we could change their modes from
6778 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
6779 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006780 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
6781 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
6782 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
6783 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
6784 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
6785 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
6786
6787 /* Loopback mixer controls */
6788 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
6789 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
6790 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
6791 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
6792 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
6793 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
6794 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
6795 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
6796 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6797 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006798 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
6799 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
6800 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
6801 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01006802
6803 /* Controls for GPIO pins, assuming they are configured as outputs */
6804 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
6805 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
6806 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
6807 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
6808
Jonathan Woithe92621f12006-02-28 11:47:47 +01006809 /* Switches to allow the digital IO pins to be enabled. The datasheet
6810 * is ambigious as to which NID is which; testing on laptops which
Kailang Yangea1fb292008-08-26 12:58:38 +02006811 * make this output available should provide clarification.
Jonathan Woithe92621f12006-02-28 11:47:47 +01006812 */
6813 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
6814 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
6815
Jonathan Woithef8225f62008-01-08 12:16:54 +01006816 /* A switch allowing EAPD to be enabled. Some laptops seem to use
6817 * this output to turn on an external amplifier.
6818 */
6819 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
6820 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
6821
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006822 { } /* end */
6823};
6824static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01006825 /* Enable all GPIOs as outputs with an initial value of 0 */
6826 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
6827 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6828 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
6829
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006830 /* Enable retasking pins as output, initially without power amp */
6831 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6832 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6833 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6834 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6835 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6836 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6837
Jonathan Woithe92621f12006-02-28 11:47:47 +01006838 /* Disable digital (SPDIF) pins initially, but users can enable
6839 * them via a mixer switch. In the case of SPDIF-out, this initverb
6840 * payload also sets the generation to 0, output to be in "consumer"
6841 * PCM format, copyright asserted, no pre-emphasis and no validity
6842 * control.
6843 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006844 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6845 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6846
Kailang Yangea1fb292008-08-26 12:58:38 +02006847 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006848 * OUT1 sum bus when acting as an output.
6849 */
6850 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6851 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
6852 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6853 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
6854
6855 /* Start with output sum widgets muted and their output gains at min */
6856 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6857 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6858 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6859 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6860 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6861 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6862 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6863 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6864 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6865
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006866 /* Unmute retasking pin widget output buffers since the default
6867 * state appears to be output. As the pin mode is changed by the
6868 * user the pin mode control will take care of enabling the pin's
6869 * input/output buffers as needed.
6870 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006871 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6872 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6873 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6874 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6875 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6876 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6877 /* Also unmute the mono-out pin widget */
6878 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6879
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006880 /* Mute capture amp left and right */
6881 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006882 /* Set ADC connection select to match default mixer setting (mic1
6883 * pin)
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006884 */
6885 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6886
6887 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01006888 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006889 */
6890 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6891 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6892
6893 /* Mute all inputs to mixer widget (even unconnected ones) */
6894 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6895 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6896 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6897 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6898 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6899 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6900 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6901 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6902
6903 { }
6904};
6905#endif
6906
Takashi Iwai63300792008-01-24 15:31:36 +01006907#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
6908#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07006909
Takashi Iwaia3bcba32005-12-06 19:05:29 +01006910#define alc260_pcm_digital_playback alc880_pcm_digital_playback
6911#define alc260_pcm_digital_capture alc880_pcm_digital_capture
6912
Kailang Yangdf694da2005-12-05 19:42:22 +01006913/*
6914 * for BIOS auto-configuration
6915 */
6916
6917static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai863b4512008-10-21 17:01:47 +02006918 const char *pfx, int *vol_bits)
Kailang Yangdf694da2005-12-05 19:42:22 +01006919{
6920 hda_nid_t nid_vol;
6921 unsigned long vol_val, sw_val;
Kailang Yangdf694da2005-12-05 19:42:22 +01006922 int err;
6923
6924 if (nid >= 0x0f && nid < 0x11) {
6925 nid_vol = nid - 0x7;
6926 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
6927 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
6928 } else if (nid == 0x11) {
6929 nid_vol = nid - 0x7;
6930 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
6931 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
6932 } else if (nid >= 0x12 && nid <= 0x15) {
6933 nid_vol = 0x08;
6934 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
6935 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
6936 } else
6937 return 0; /* N/A */
Kailang Yangea1fb292008-08-26 12:58:38 +02006938
Takashi Iwai863b4512008-10-21 17:01:47 +02006939 if (!(*vol_bits & (1 << nid_vol))) {
6940 /* first control for the volume widget */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02006941 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, vol_val);
Takashi Iwai863b4512008-10-21 17:01:47 +02006942 if (err < 0)
6943 return err;
6944 *vol_bits |= (1 << nid_vol);
6945 }
Takashi Iwai0afe5f82009-10-02 09:20:00 +02006946 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, sw_val);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006947 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006948 return err;
6949 return 1;
6950}
6951
6952/* add playback controls from the parsed DAC table */
6953static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
6954 const struct auto_pin_cfg *cfg)
6955{
6956 hda_nid_t nid;
6957 int err;
Takashi Iwai863b4512008-10-21 17:01:47 +02006958 int vols = 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01006959
6960 spec->multiout.num_dacs = 1;
6961 spec->multiout.dac_nids = spec->private_dac_nids;
6962 spec->multiout.dac_nids[0] = 0x02;
6963
6964 nid = cfg->line_out_pins[0];
6965 if (nid) {
Takashi Iwai23112d62009-08-25 16:07:08 +02006966 const char *pfx;
6967 if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
6968 pfx = "Master";
6969 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
6970 pfx = "Speaker";
6971 else
6972 pfx = "Front";
6973 err = alc260_add_playback_controls(spec, nid, pfx, &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006974 if (err < 0)
6975 return err;
6976 }
6977
Takashi Iwai82bc9552006-03-21 11:24:42 +01006978 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006979 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02006980 err = alc260_add_playback_controls(spec, nid, "Speaker", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006981 if (err < 0)
6982 return err;
6983 }
6984
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006985 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006986 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02006987 err = alc260_add_playback_controls(spec, nid, "Headphone",
6988 &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006989 if (err < 0)
6990 return err;
6991 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006992 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01006993}
6994
6995/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +02006996static int alc260_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yangdf694da2005-12-05 19:42:22 +01006997 const struct auto_pin_cfg *cfg)
6998{
Takashi Iwai05f5f472009-08-25 13:10:18 +02006999 return alc_auto_create_input_ctls(codec, cfg, 0x07, 0x04, 0x05);
Kailang Yangdf694da2005-12-05 19:42:22 +01007000}
7001
7002static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
7003 hda_nid_t nid, int pin_type,
7004 int sel_idx)
7005{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007006 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01007007 /* need the manual connection? */
7008 if (nid >= 0x12) {
7009 int idx = nid - 0x12;
7010 snd_hda_codec_write(codec, idx + 0x0b, 0,
7011 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01007012 }
7013}
7014
7015static void alc260_auto_init_multi_out(struct hda_codec *codec)
7016{
7017 struct alc_spec *spec = codec->spec;
7018 hda_nid_t nid;
7019
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007020 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007021 if (nid) {
7022 int pin_type = get_pin_type(spec->autocfg.line_out_type);
7023 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
7024 }
Kailang Yangea1fb292008-08-26 12:58:38 +02007025
Takashi Iwai82bc9552006-03-21 11:24:42 +01007026 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007027 if (nid)
7028 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
7029
Takashi Iwaieb06ed82006-09-20 17:10:27 +02007030 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007031 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007032 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007033}
Kailang Yangdf694da2005-12-05 19:42:22 +01007034
7035#define ALC260_PIN_CD_NID 0x16
7036static void alc260_auto_init_analog_input(struct hda_codec *codec)
7037{
7038 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02007039 struct auto_pin_cfg *cfg = &spec->autocfg;
Kailang Yangdf694da2005-12-05 19:42:22 +01007040 int i;
7041
Takashi Iwai66ceeb62010-08-30 13:05:52 +02007042 for (i = 0; i < cfg->num_inputs; i++) {
7043 hda_nid_t nid = cfg->inputs[i].pin;
Kailang Yangdf694da2005-12-05 19:42:22 +01007044 if (nid >= 0x12) {
Takashi Iwai30ea0982010-09-16 18:47:56 +02007045 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwaie82c0252009-03-23 15:17:38 +01007046 if (nid != ALC260_PIN_CD_NID &&
7047 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007048 snd_hda_codec_write(codec, nid, 0,
7049 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01007050 AMP_OUT_MUTE);
7051 }
7052 }
7053}
7054
Takashi Iwai7f311a42010-04-09 17:32:23 +02007055#define alc260_auto_init_input_src alc880_auto_init_input_src
7056
Kailang Yangdf694da2005-12-05 19:42:22 +01007057/*
7058 * generic initialization of ADC, input mixers and output mixers
7059 */
7060static struct hda_verb alc260_volume_init_verbs[] = {
7061 /*
7062 * Unmute ADC0-1 and set the default input to mic-in
7063 */
7064 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
7065 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7066 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
7067 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02007068
Kailang Yangdf694da2005-12-05 19:42:22 +01007069 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
7070 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007071 * Note: PASD motherboards uses the Line In 2 as the input for
7072 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01007073 */
7074 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02007075 /* mute analog inputs */
7076 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7077 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7078 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7079 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7080 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01007081
7082 /*
7083 * Set up output mixers (0x08 - 0x0a)
7084 */
7085 /* set vol=0 to output mixers */
7086 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7087 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7088 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7089 /* set up input amps for analog loopback */
7090 /* Amp Indices: DAC = 0, mixer = 1 */
7091 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7092 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7093 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7094 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7095 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7096 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +02007097
Kailang Yangdf694da2005-12-05 19:42:22 +01007098 { }
7099};
7100
7101static int alc260_parse_auto_config(struct hda_codec *codec)
7102{
7103 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007104 int err;
7105 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
7106
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007107 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
7108 alc260_ignore);
7109 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01007110 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007111 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
7112 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01007113 return err;
Takashi Iwai603c4012008-07-30 15:01:44 +02007114 if (!spec->kctls.list)
Kailang Yangdf694da2005-12-05 19:42:22 +01007115 return 0; /* can't find valid BIOS pin config */
Takashi Iwai05f5f472009-08-25 13:10:18 +02007116 err = alc260_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007117 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01007118 return err;
7119
7120 spec->multiout.max_channels = 2;
7121
Takashi Iwai0852d7a2009-02-11 11:35:15 +01007122 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +01007123 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
Takashi Iwai603c4012008-07-30 15:01:44 +02007124 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01007125 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +01007126
Takashi Iwaid88897e2008-10-31 15:01:37 +01007127 add_verb(spec, alc260_volume_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +01007128
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007129 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02007130 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007131
Kailang Yang6227cdc2010-02-25 08:36:52 +01007132 alc_ssid_check(codec, 0x10, 0x15, 0x0f, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02007133
Kailang Yangdf694da2005-12-05 19:42:22 +01007134 return 1;
7135}
7136
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007137/* additional initialization for auto-configuration model */
7138static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01007139{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007140 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007141 alc260_auto_init_multi_out(codec);
7142 alc260_auto_init_analog_input(codec);
Takashi Iwai7f311a42010-04-09 17:32:23 +02007143 alc260_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +02007144 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007145 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02007146 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01007147}
7148
Takashi Iwaicb53c622007-08-10 17:21:45 +02007149#ifdef CONFIG_SND_HDA_POWER_SAVE
7150static struct hda_amp_list alc260_loopbacks[] = {
7151 { 0x07, HDA_INPUT, 0 },
7152 { 0x07, HDA_INPUT, 1 },
7153 { 0x07, HDA_INPUT, 2 },
7154 { 0x07, HDA_INPUT, 3 },
7155 { 0x07, HDA_INPUT, 4 },
7156 { } /* end */
7157};
7158#endif
7159
Kailang Yangdf694da2005-12-05 19:42:22 +01007160/*
Takashi Iwaifc091762010-08-04 23:53:36 +02007161 * Pin config fixes
7162 */
7163enum {
7164 PINFIX_HP_DC5750,
7165};
7166
Takashi Iwaifc091762010-08-04 23:53:36 +02007167static const struct alc_fixup alc260_fixups[] = {
7168 [PINFIX_HP_DC5750] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01007169 .type = ALC_FIXUP_PINS,
7170 .v.pins = (const struct alc_pincfg[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +02007171 { 0x11, 0x90130110 }, /* speaker */
7172 { }
7173 }
Takashi Iwaifc091762010-08-04 23:53:36 +02007174 },
7175};
7176
7177static struct snd_pci_quirk alc260_fixup_tbl[] = {
7178 SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750),
7179 {}
7180};
7181
7182/*
Kailang Yangdf694da2005-12-05 19:42:22 +01007183 * ALC260 configurations
7184 */
Takashi Iwaiea734962011-01-17 11:29:34 +01007185static const char * const alc260_models[ALC260_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007186 [ALC260_BASIC] = "basic",
7187 [ALC260_HP] = "hp",
7188 [ALC260_HP_3013] = "hp-3013",
Takashi Iwai2922c9a2008-08-27 18:12:42 +02007189 [ALC260_HP_DC7600] = "hp-dc7600",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007190 [ALC260_FUJITSU_S702X] = "fujitsu",
7191 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007192 [ALC260_WILL] = "will",
7193 [ALC260_REPLACER_672V] = "replacer",
Michael Schwingencc959482009-02-22 18:58:45 +01007194 [ALC260_FAVORIT100] = "favorit100",
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01007195#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007196 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01007197#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007198 [ALC260_AUTO] = "auto",
7199};
7200
7201static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01007202 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Daniel T Chen950200e2009-12-13 14:11:02 -05007203 SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007204 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Michael Schwingencc959482009-02-22 18:58:45 +01007205 SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100),
Takashi Iwai9720b712007-03-13 21:46:23 +01007206 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwai4ac55982009-11-10 16:08:45 +01007207 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007208 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
Jaroslav Kysela34ec8a02008-07-10 14:49:19 +02007209 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
Kailang Yang3f878302008-08-26 13:02:23 +02007210 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007211 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
7212 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
7213 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
7214 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
7215 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
7216 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
7217 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
7218 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
7219 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007220 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007221 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02007222 {}
7223};
7224
Kailang Yangdf694da2005-12-05 19:42:22 +01007225static struct alc_config_preset alc260_presets[] = {
7226 [ALC260_BASIC] = {
7227 .mixers = { alc260_base_output_mixer,
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007228 alc260_input_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01007229 .init_verbs = { alc260_init_verbs },
7230 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7231 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007232 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
Takashi Iwai9c4cc0b2010-03-15 09:07:52 +01007233 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01007234 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7235 .channel_mode = alc260_modes,
7236 .input_mux = &alc260_capture_source,
7237 },
7238 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01007239 .mixers = { alc260_hp_output_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007240 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01007241 .init_verbs = { alc260_init_verbs,
7242 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01007243 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7244 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007245 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7246 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01007247 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7248 .channel_mode = alc260_modes,
7249 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01007250 .unsol_event = alc260_hp_unsol_event,
7251 .init_hook = alc260_hp_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01007252 },
Kailang Yang3f878302008-08-26 13:02:23 +02007253 [ALC260_HP_DC7600] = {
7254 .mixers = { alc260_hp_dc7600_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007255 alc260_input_mixer },
Kailang Yang3f878302008-08-26 13:02:23 +02007256 .init_verbs = { alc260_init_verbs,
7257 alc260_hp_dc7600_verbs },
7258 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7259 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007260 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7261 .adc_nids = alc260_adc_nids_alt,
Kailang Yang3f878302008-08-26 13:02:23 +02007262 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7263 .channel_mode = alc260_modes,
7264 .input_mux = &alc260_capture_source,
7265 .unsol_event = alc260_hp_3012_unsol_event,
7266 .init_hook = alc260_hp_3012_automute,
7267 },
Kailang Yangdf694da2005-12-05 19:42:22 +01007268 [ALC260_HP_3013] = {
7269 .mixers = { alc260_hp_3013_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007270 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01007271 .init_verbs = { alc260_hp_3013_init_verbs,
7272 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01007273 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7274 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007275 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7276 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01007277 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7278 .channel_mode = alc260_modes,
7279 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01007280 .unsol_event = alc260_hp_3013_unsol_event,
7281 .init_hook = alc260_hp_3013_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01007282 },
7283 [ALC260_FUJITSU_S702X] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007284 .mixers = { alc260_fujitsu_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01007285 .init_verbs = { alc260_fujitsu_init_verbs },
7286 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7287 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01007288 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7289 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01007290 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7291 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007292 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
7293 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01007294 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007295 [ALC260_ACER] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007296 .mixers = { alc260_acer_mixer },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007297 .init_verbs = { alc260_acer_init_verbs },
7298 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7299 .dac_nids = alc260_dac_nids,
7300 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7301 .adc_nids = alc260_dual_adc_nids,
7302 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7303 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007304 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
7305 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007306 },
Michael Schwingencc959482009-02-22 18:58:45 +01007307 [ALC260_FAVORIT100] = {
7308 .mixers = { alc260_favorit100_mixer },
7309 .init_verbs = { alc260_favorit100_init_verbs },
7310 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7311 .dac_nids = alc260_dac_nids,
7312 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7313 .adc_nids = alc260_dual_adc_nids,
7314 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7315 .channel_mode = alc260_modes,
7316 .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources),
7317 .input_mux = alc260_favorit100_capture_sources,
7318 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007319 [ALC260_WILL] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007320 .mixers = { alc260_will_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007321 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
7322 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7323 .dac_nids = alc260_dac_nids,
7324 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
7325 .adc_nids = alc260_adc_nids,
7326 .dig_out_nid = ALC260_DIGOUT_NID,
7327 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7328 .channel_mode = alc260_modes,
7329 .input_mux = &alc260_capture_source,
7330 },
7331 [ALC260_REPLACER_672V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007332 .mixers = { alc260_replacer_672v_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007333 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
7334 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7335 .dac_nids = alc260_dac_nids,
7336 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
7337 .adc_nids = alc260_adc_nids,
7338 .dig_out_nid = ALC260_DIGOUT_NID,
7339 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7340 .channel_mode = alc260_modes,
7341 .input_mux = &alc260_capture_source,
7342 .unsol_event = alc260_replacer_672v_unsol_event,
7343 .init_hook = alc260_replacer_672v_automute,
7344 },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01007345#ifdef CONFIG_SND_DEBUG
7346 [ALC260_TEST] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007347 .mixers = { alc260_test_mixer },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01007348 .init_verbs = { alc260_test_init_verbs },
7349 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
7350 .dac_nids = alc260_test_dac_nids,
7351 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
7352 .adc_nids = alc260_test_adc_nids,
7353 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7354 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007355 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
7356 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01007357 },
7358#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01007359};
7360
Linus Torvalds1da177e2005-04-16 15:20:36 -07007361static int patch_alc260(struct hda_codec *codec)
7362{
7363 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007364 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007365
Takashi Iwaie560d8d2005-09-09 14:21:46 +02007366 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007367 if (spec == NULL)
7368 return -ENOMEM;
7369
7370 codec->spec = spec;
7371
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007372 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
7373 alc260_models,
7374 alc260_cfg_tbl);
7375 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02007376 snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai6c627f32009-05-18 12:33:36 +02007377 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +01007378 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02007379 }
7380
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01007381 if (board_config == ALC260_AUTO) {
7382 alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups);
7383 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
7384 }
Takashi Iwaifc091762010-08-04 23:53:36 +02007385
Kailang Yangdf694da2005-12-05 19:42:22 +01007386 if (board_config == ALC260_AUTO) {
7387 /* automatic parse from the BIOS config */
7388 err = alc260_parse_auto_config(codec);
7389 if (err < 0) {
7390 alc_free(codec);
7391 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007392 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007393 printk(KERN_INFO
7394 "hda_codec: Cannot set up configuration "
7395 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01007396 board_config = ALC260_BASIC;
7397 }
Takashi Iwai16ded522005-06-10 19:58:24 +02007398 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007399
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09007400 err = snd_hda_attach_beep_device(codec, 0x1);
7401 if (err < 0) {
7402 alc_free(codec);
7403 return err;
7404 }
7405
Kailang Yangdf694da2005-12-05 19:42:22 +01007406 if (board_config != ALC260_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02007407 setup_preset(codec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007408
Linus Torvalds1da177e2005-04-16 15:20:36 -07007409 spec->stream_analog_playback = &alc260_pcm_analog_playback;
7410 spec->stream_analog_capture = &alc260_pcm_analog_capture;
Jonathan Woithe53bacfb2010-08-08 00:17:05 +09307411 spec->stream_analog_alt_capture = &alc260_pcm_analog_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007412
Takashi Iwaia3bcba32005-12-06 19:05:29 +01007413 spec->stream_digital_playback = &alc260_pcm_digital_playback;
7414 spec->stream_digital_capture = &alc260_pcm_digital_capture;
7415
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01007416 if (!spec->adc_nids && spec->input_mux) {
7417 /* check whether NID 0x04 is valid */
7418 unsigned int wcap = get_wcaps(codec, 0x04);
Takashi Iwaia22d5432009-07-27 12:54:26 +02007419 wcap = get_wcaps_type(wcap);
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01007420 /* get type */
7421 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
7422 spec->adc_nids = alc260_adc_nids_alt;
7423 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
7424 } else {
7425 spec->adc_nids = alc260_adc_nids;
7426 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
7427 }
7428 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02007429 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007430 set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007431
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01007432 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwaifc091762010-08-04 23:53:36 +02007433
Takashi Iwai2134ea42008-01-10 16:53:55 +01007434 spec->vmaster_nid = 0x08;
7435
Linus Torvalds1da177e2005-04-16 15:20:36 -07007436 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01007437 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007438 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02007439#ifdef CONFIG_SND_HDA_POWER_SAVE
7440 if (!spec->loopback.amplist)
7441 spec->loopback.amplist = alc260_loopbacks;
7442#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007443
7444 return 0;
7445}
7446
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007447
Linus Torvalds1da177e2005-04-16 15:20:36 -07007448/*
Takashi Iwai4953550a2009-06-30 15:28:30 +02007449 * ALC882/883/885/888/889 support
Linus Torvalds1da177e2005-04-16 15:20:36 -07007450 *
7451 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
7452 * configuration. Each pin widget can choose any input DACs and a mixer.
7453 * Each ADC is connected from a mixer of all inputs. This makes possible
7454 * 6-channel independent captures.
7455 *
7456 * In addition, an independent DAC for the multi-playback (not used in this
7457 * driver yet).
7458 */
Kailang Yangdf694da2005-12-05 19:42:22 +01007459#define ALC882_DIGOUT_NID 0x06
7460#define ALC882_DIGIN_NID 0x0a
Takashi Iwai4953550a2009-06-30 15:28:30 +02007461#define ALC883_DIGOUT_NID ALC882_DIGOUT_NID
7462#define ALC883_DIGIN_NID ALC882_DIGIN_NID
7463#define ALC1200_DIGOUT_NID 0x10
7464
Linus Torvalds1da177e2005-04-16 15:20:36 -07007465
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01007466static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007467 { 8, NULL }
7468};
7469
Takashi Iwai4953550a2009-06-30 15:28:30 +02007470/* DACs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007471static hda_nid_t alc882_dac_nids[4] = {
7472 /* front, rear, clfe, rear_surr */
7473 0x02, 0x03, 0x04, 0x05
7474};
Takashi Iwai4953550a2009-06-30 15:28:30 +02007475#define alc883_dac_nids alc882_dac_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007476
Takashi Iwai4953550a2009-06-30 15:28:30 +02007477/* ADCs */
Kailang Yangdf694da2005-12-05 19:42:22 +01007478#define alc882_adc_nids alc880_adc_nids
7479#define alc882_adc_nids_alt alc880_adc_nids_alt
Takashi Iwai4953550a2009-06-30 15:28:30 +02007480#define alc883_adc_nids alc882_adc_nids_alt
7481static hda_nid_t alc883_adc_nids_alt[1] = { 0x08 };
7482static hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 };
7483#define alc889_adc_nids alc880_adc_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007484
Takashi Iwaie1406342008-02-11 18:32:32 +01007485static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
7486static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
Takashi Iwai4953550a2009-06-30 15:28:30 +02007487#define alc883_capsrc_nids alc882_capsrc_nids_alt
7488static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
7489#define alc889_capsrc_nids alc882_capsrc_nids
Takashi Iwaie1406342008-02-11 18:32:32 +01007490
Linus Torvalds1da177e2005-04-16 15:20:36 -07007491/* input MUX */
7492/* FIXME: should be a matrix-type input source selection */
7493
7494static struct hda_input_mux alc882_capture_source = {
7495 .num_items = 4,
7496 .items = {
7497 { "Mic", 0x0 },
7498 { "Front Mic", 0x1 },
7499 { "Line", 0x2 },
7500 { "CD", 0x4 },
7501 },
7502};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007503
Takashi Iwai4953550a2009-06-30 15:28:30 +02007504#define alc883_capture_source alc882_capture_source
7505
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007506static struct hda_input_mux alc889_capture_source = {
7507 .num_items = 3,
7508 .items = {
7509 { "Front Mic", 0x0 },
7510 { "Mic", 0x3 },
7511 { "Line", 0x2 },
7512 },
7513};
7514
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007515static struct hda_input_mux mb5_capture_source = {
7516 .num_items = 3,
7517 .items = {
7518 { "Mic", 0x1 },
Alex Murrayb8f171e2010-06-14 12:08:43 +09307519 { "Line", 0x7 },
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007520 { "CD", 0x4 },
7521 },
7522};
7523
Luke Yelaviche458b1f2010-02-12 16:28:29 +11007524static struct hda_input_mux macmini3_capture_source = {
7525 .num_items = 2,
7526 .items = {
7527 { "Line", 0x2 },
7528 { "CD", 0x4 },
7529 },
7530};
7531
Takashi Iwai4953550a2009-06-30 15:28:30 +02007532static struct hda_input_mux alc883_3stack_6ch_intel = {
7533 .num_items = 4,
7534 .items = {
7535 { "Mic", 0x1 },
7536 { "Front Mic", 0x0 },
7537 { "Line", 0x2 },
7538 { "CD", 0x4 },
7539 },
7540};
7541
7542static struct hda_input_mux alc883_lenovo_101e_capture_source = {
7543 .num_items = 2,
7544 .items = {
7545 { "Mic", 0x1 },
7546 { "Line", 0x2 },
7547 },
7548};
7549
7550static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
7551 .num_items = 4,
7552 .items = {
7553 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +01007554 { "Internal Mic", 0x1 },
Takashi Iwai4953550a2009-06-30 15:28:30 +02007555 { "Line", 0x2 },
7556 { "CD", 0x4 },
7557 },
7558};
7559
7560static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
7561 .num_items = 2,
7562 .items = {
7563 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +01007564 { "Internal Mic", 0x1 },
Takashi Iwai4953550a2009-06-30 15:28:30 +02007565 },
7566};
7567
7568static struct hda_input_mux alc883_lenovo_sky_capture_source = {
7569 .num_items = 3,
7570 .items = {
7571 { "Mic", 0x0 },
7572 { "Front Mic", 0x1 },
7573 { "Line", 0x4 },
7574 },
7575};
7576
7577static struct hda_input_mux alc883_asus_eee1601_capture_source = {
7578 .num_items = 2,
7579 .items = {
7580 { "Mic", 0x0 },
7581 { "Line", 0x2 },
7582 },
7583};
7584
7585static struct hda_input_mux alc889A_mb31_capture_source = {
7586 .num_items = 2,
7587 .items = {
7588 { "Mic", 0x0 },
7589 /* Front Mic (0x01) unused */
7590 { "Line", 0x2 },
7591 /* Line 2 (0x03) unused */
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02007592 /* CD (0x04) unused? */
Takashi Iwai4953550a2009-06-30 15:28:30 +02007593 },
7594};
7595
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07007596static struct hda_input_mux alc889A_imac91_capture_source = {
7597 .num_items = 2,
7598 .items = {
7599 { "Mic", 0x01 },
7600 { "Line", 0x2 }, /* Not sure! */
7601 },
7602};
7603
Takashi Iwai4953550a2009-06-30 15:28:30 +02007604/*
7605 * 2ch mode
7606 */
7607static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
7608 { 2, NULL }
7609};
7610
Kailang Yangdf694da2005-12-05 19:42:22 +01007611/*
Kailang Yang272a5272007-05-14 11:00:38 +02007612 * 2ch mode
7613 */
7614static struct hda_verb alc882_3ST_ch2_init[] = {
7615 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7616 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7617 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7618 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7619 { } /* end */
7620};
7621
7622/*
Takashi Iwai4953550a2009-06-30 15:28:30 +02007623 * 4ch mode
7624 */
7625static struct hda_verb alc882_3ST_ch4_init[] = {
7626 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7627 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7628 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7629 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7630 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7631 { } /* end */
7632};
7633
7634/*
Kailang Yang272a5272007-05-14 11:00:38 +02007635 * 6ch mode
7636 */
7637static struct hda_verb alc882_3ST_ch6_init[] = {
7638 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7639 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7640 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7641 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7642 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7643 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7644 { } /* end */
7645};
7646
Takashi Iwai4953550a2009-06-30 15:28:30 +02007647static struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
Kailang Yang272a5272007-05-14 11:00:38 +02007648 { 2, alc882_3ST_ch2_init },
Takashi Iwai4953550a2009-06-30 15:28:30 +02007649 { 4, alc882_3ST_ch4_init },
Kailang Yang272a5272007-05-14 11:00:38 +02007650 { 6, alc882_3ST_ch6_init },
7651};
7652
Takashi Iwai4953550a2009-06-30 15:28:30 +02007653#define alc883_3ST_6ch_modes alc882_3ST_6ch_modes
7654
Kailang Yang272a5272007-05-14 11:00:38 +02007655/*
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307656 * 2ch mode
7657 */
7658static struct hda_verb alc883_3ST_ch2_clevo_init[] = {
7659 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
7660 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7661 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7662 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7663 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7664 { } /* end */
7665};
7666
7667/*
7668 * 4ch mode
7669 */
7670static struct hda_verb alc883_3ST_ch4_clevo_init[] = {
7671 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7672 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7673 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7674 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7675 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7676 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7677 { } /* end */
7678};
7679
7680/*
7681 * 6ch mode
7682 */
7683static struct hda_verb alc883_3ST_ch6_clevo_init[] = {
7684 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7685 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7686 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7687 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7688 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7689 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7690 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7691 { } /* end */
7692};
7693
7694static struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
7695 { 2, alc883_3ST_ch2_clevo_init },
7696 { 4, alc883_3ST_ch4_clevo_init },
7697 { 6, alc883_3ST_ch6_clevo_init },
7698};
7699
7700
7701/*
Kailang Yangdf694da2005-12-05 19:42:22 +01007702 * 6ch mode
7703 */
7704static struct hda_verb alc882_sixstack_ch6_init[] = {
7705 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7706 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7707 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7708 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7709 { } /* end */
7710};
7711
7712/*
7713 * 8ch mode
7714 */
7715static struct hda_verb alc882_sixstack_ch8_init[] = {
7716 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7717 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7718 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7719 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7720 { } /* end */
7721};
7722
7723static struct hda_channel_mode alc882_sixstack_modes[2] = {
7724 { 6, alc882_sixstack_ch6_init },
7725 { 8, alc882_sixstack_ch8_init },
7726};
7727
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08007728
7729/* Macbook Air 2,1 */
7730
7731static struct hda_channel_mode alc885_mba21_ch_modes[1] = {
7732 { 2, NULL },
7733};
7734
Takashi Iwai87350ad2007-08-16 18:19:38 +02007735/*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04007736 * macbook pro ALC885 can switch LineIn to LineOut without losing Mic
Takashi Iwai87350ad2007-08-16 18:19:38 +02007737 */
7738
7739/*
7740 * 2ch mode
7741 */
7742static struct hda_verb alc885_mbp_ch2_init[] = {
7743 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7744 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7745 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7746 { } /* end */
7747};
7748
7749/*
Takashi Iwaia3f730af2009-08-31 08:15:26 +02007750 * 4ch mode
Takashi Iwai87350ad2007-08-16 18:19:38 +02007751 */
Takashi Iwaia3f730af2009-08-31 08:15:26 +02007752static struct hda_verb alc885_mbp_ch4_init[] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007753 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7754 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7755 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7756 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7757 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7758 { } /* end */
7759};
7760
Takashi Iwaia3f730af2009-08-31 08:15:26 +02007761static struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007762 { 2, alc885_mbp_ch2_init },
Takashi Iwaia3f730af2009-08-31 08:15:26 +02007763 { 4, alc885_mbp_ch4_init },
Takashi Iwai87350ad2007-08-16 18:19:38 +02007764};
7765
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007766/*
7767 * 2ch
7768 * Speakers/Woofer/HP = Front
7769 * LineIn = Input
7770 */
7771static struct hda_verb alc885_mb5_ch2_init[] = {
7772 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7773 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7774 { } /* end */
7775};
7776
7777/*
7778 * 6ch mode
7779 * Speakers/HP = Front
7780 * Woofer = LFE
7781 * LineIn = Surround
7782 */
7783static struct hda_verb alc885_mb5_ch6_init[] = {
7784 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7785 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7786 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7787 { } /* end */
7788};
7789
7790static struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
7791 { 2, alc885_mb5_ch2_init },
7792 { 6, alc885_mb5_ch6_init },
7793};
Takashi Iwai87350ad2007-08-16 18:19:38 +02007794
Takashi Iwaid01aecd2010-02-23 08:07:15 +01007795#define alc885_macmini3_6ch_modes alc885_mb5_6ch_modes
Takashi Iwai4953550a2009-06-30 15:28:30 +02007796
7797/*
7798 * 2ch mode
7799 */
7800static struct hda_verb alc883_4ST_ch2_init[] = {
7801 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7802 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7803 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7804 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7805 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7806 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7807 { } /* end */
7808};
7809
7810/*
7811 * 4ch mode
7812 */
7813static struct hda_verb alc883_4ST_ch4_init[] = {
7814 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7815 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7816 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7817 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7818 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7819 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7820 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7821 { } /* end */
7822};
7823
7824/*
7825 * 6ch mode
7826 */
7827static struct hda_verb alc883_4ST_ch6_init[] = {
7828 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7829 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7830 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7831 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7832 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7833 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7834 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7835 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7836 { } /* end */
7837};
7838
7839/*
7840 * 8ch mode
7841 */
7842static struct hda_verb alc883_4ST_ch8_init[] = {
7843 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7844 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7845 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7846 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7847 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7848 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7849 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7850 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7851 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7852 { } /* end */
7853};
7854
7855static struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
7856 { 2, alc883_4ST_ch2_init },
7857 { 4, alc883_4ST_ch4_init },
7858 { 6, alc883_4ST_ch6_init },
7859 { 8, alc883_4ST_ch8_init },
7860};
7861
7862
7863/*
7864 * 2ch mode
7865 */
7866static struct hda_verb alc883_3ST_ch2_intel_init[] = {
7867 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7868 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7869 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7870 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7871 { } /* end */
7872};
7873
7874/*
7875 * 4ch mode
7876 */
7877static struct hda_verb alc883_3ST_ch4_intel_init[] = {
7878 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7879 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7880 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7881 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7882 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7883 { } /* end */
7884};
7885
7886/*
7887 * 6ch mode
7888 */
7889static struct hda_verb alc883_3ST_ch6_intel_init[] = {
7890 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7891 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7892 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
7893 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7894 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7895 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7896 { } /* end */
7897};
7898
7899static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
7900 { 2, alc883_3ST_ch2_intel_init },
7901 { 4, alc883_3ST_ch4_intel_init },
7902 { 6, alc883_3ST_ch6_intel_init },
7903};
7904
7905/*
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007906 * 2ch mode
7907 */
7908static struct hda_verb alc889_ch2_intel_init[] = {
7909 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7910 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 },
7911 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 },
7912 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00 },
7913 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7914 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7915 { } /* end */
7916};
7917
7918/*
Takashi Iwai4953550a2009-06-30 15:28:30 +02007919 * 6ch mode
7920 */
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007921static struct hda_verb alc889_ch6_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007922 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7923 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7924 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7925 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7926 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007927 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7928 { } /* end */
7929};
7930
7931/*
7932 * 8ch mode
7933 */
7934static struct hda_verb alc889_ch8_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007935 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7936 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7937 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7938 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7939 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x03 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007940 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7941 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007942 { } /* end */
7943};
7944
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007945static struct hda_channel_mode alc889_8ch_intel_modes[3] = {
7946 { 2, alc889_ch2_intel_init },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007947 { 6, alc889_ch6_intel_init },
7948 { 8, alc889_ch8_intel_init },
7949};
7950
7951/*
7952 * 6ch mode
7953 */
Takashi Iwai4953550a2009-06-30 15:28:30 +02007954static struct hda_verb alc883_sixstack_ch6_init[] = {
7955 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7956 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7957 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7958 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7959 { } /* end */
7960};
7961
7962/*
7963 * 8ch mode
7964 */
7965static struct hda_verb alc883_sixstack_ch8_init[] = {
7966 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7967 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7968 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7969 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7970 { } /* end */
7971};
7972
7973static struct hda_channel_mode alc883_sixstack_modes[2] = {
7974 { 6, alc883_sixstack_ch6_init },
7975 { 8, alc883_sixstack_ch8_init },
7976};
7977
7978
Linus Torvalds1da177e2005-04-16 15:20:36 -07007979/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
7980 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
7981 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01007982static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02007983 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007984 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007985 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007986 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007987 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7988 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007989 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7990 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007991 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007992 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007993 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7994 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7995 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7996 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7997 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7998 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01007999 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07008000 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8001 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008002 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07008003 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07008004 { } /* end */
8005};
8006
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008007/* Macbook Air 2,1 same control for HP and internal Speaker */
8008
8009static struct snd_kcontrol_new alc885_mba21_mixer[] = {
8010 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8011 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT),
8012 { }
8013};
8014
8015
Takashi Iwai87350ad2007-08-16 18:19:38 +02008016static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwaia3f730af2009-08-31 08:15:26 +02008017 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8018 HDA_BIND_MUTE ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
8019 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
8020 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT),
8021 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01008022 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8023 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02008024 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
8025 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008026 HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT),
8027 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02008028 { } /* end */
8029};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008030
8031static struct snd_kcontrol_new alc885_mb5_mixer[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008032 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8033 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
8034 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
8035 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
8036 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
8037 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
Alex Murraya76221d2010-01-13 23:15:03 +10308038 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
8039 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
Alex Murrayb8f171e2010-06-14 12:08:43 +09308040 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
8041 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008042 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8043 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008044 HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT),
8045 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0x00, HDA_INPUT),
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008046 { } /* end */
8047};
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008048
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008049static struct snd_kcontrol_new alc885_macmini3_mixer[] = {
8050 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8051 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
8052 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
8053 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
8054 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
8055 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
8056 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
8057 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
8058 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
8059 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008060 HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT),
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008061 { } /* end */
8062};
8063
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008064static struct snd_kcontrol_new alc885_imac91_mixer[] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008065 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8066 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008067 { } /* end */
8068};
8069
8070
Kailang Yangbdd148a2007-05-08 15:19:08 +02008071static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
8072 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8073 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8074 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8075 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8076 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8077 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8078 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008079 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02008080 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02008081 { } /* end */
8082};
8083
Kailang Yang272a5272007-05-14 11:00:38 +02008084static struct snd_kcontrol_new alc882_targa_mixer[] = {
8085 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8086 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8087 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8088 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8089 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8090 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8091 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8092 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8093 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008094 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008095 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8096 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008097 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008098 { } /* end */
8099};
8100
8101/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
8102 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
8103 */
8104static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
8105 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8106 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8107 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8108 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
8109 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8110 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8111 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8112 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8113 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
8114 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
8115 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8116 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008117 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008118 { } /* end */
8119};
8120
Takashi Iwai914759b2007-09-06 14:52:04 +02008121static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
8122 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8123 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8124 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8125 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8126 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8127 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8128 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8129 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008130 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02008131 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02008132 { } /* end */
8133};
8134
Kailang Yangdf694da2005-12-05 19:42:22 +01008135static struct snd_kcontrol_new alc882_chmode_mixer[] = {
8136 {
8137 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8138 .name = "Channel Mode",
8139 .info = alc_ch_mode_info,
8140 .get = alc_ch_mode_get,
8141 .put = alc_ch_mode_put,
8142 },
8143 { } /* end */
8144};
8145
Takashi Iwai4953550a2009-06-30 15:28:30 +02008146static struct hda_verb alc882_base_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008147 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008148 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8149 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008150 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02008151 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8152 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008153 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02008154 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8155 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008156 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02008157 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8158 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008159
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008160 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008161 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008162 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008163 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008164 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008165 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008166 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008167 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008168 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008169 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008170 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008171 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008172 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008173 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008174 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008175 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008176 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02008177 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008178 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8179 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02008180 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008181 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8182 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02008183 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008184 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8185 /* Line-2 In: Headphone output (output 0 - 0x0c) */
8186 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8187 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8188 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008189 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02008190 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008191
8192 /* FIXME: use matrix-type input source selection */
8193 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008194 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02008195 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008196 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02008197 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai05acb862005-06-10 19:50:25 +02008198 /* ADC2: mute amp left and right */
8199 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02008200 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02008201 /* ADC3: mute amp left and right */
8202 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02008203 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008204
8205 { }
8206};
8207
Takashi Iwai4953550a2009-06-30 15:28:30 +02008208static struct hda_verb alc882_adc1_init_verbs[] = {
8209 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8210 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8211 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8212 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8213 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8214 /* ADC1: mute amp left and right */
8215 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8216 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8217 { }
8218};
8219
Takashi Iwai4b146cb2006-07-28 14:42:36 +02008220static struct hda_verb alc882_eapd_verbs[] = {
8221 /* change to EAPD mode */
8222 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008223 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008224 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02008225};
8226
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008227static struct hda_verb alc889_eapd_verbs[] = {
8228 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
8229 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
8230 { }
8231};
8232
Wu Fengguang6732bd02009-07-30 09:19:14 +02008233static struct hda_verb alc_hp15_unsol_verbs[] = {
8234 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8235 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8236 {}
8237};
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008238
8239static struct hda_verb alc885_init_verbs[] = {
8240 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Kailang Yang88102f32010-02-04 14:12:58 +01008241 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8242 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008243 /* Rear mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008244 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8245 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008246 /* CLFE mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008247 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8248 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008249 /* Side mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008250 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8251 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008252
8253 /* Front HP Pin: output 0 (0x0c) */
Wu Fengguang6732bd02009-07-30 09:19:14 +02008254 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008255 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8256 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8257 /* Front Pin: output 0 (0x0c) */
8258 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8259 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8260 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8261 /* Rear Pin: output 1 (0x0d) */
8262 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8263 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8264 {0x19, AC_VERB_SET_CONNECT_SEL, 0x01},
8265 /* CLFE Pin: output 2 (0x0e) */
8266 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8267 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8268 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
8269 /* Side Pin: output 3 (0x0f) */
8270 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8271 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8272 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
8273 /* Mic (rear) pin: input vref at 80% */
8274 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8275 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8276 /* Front Mic pin: input vref at 80% */
8277 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8278 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8279 /* Line In pin: input */
8280 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8281 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8282
8283 /* Mixer elements: 0x18, , 0x1a, 0x1b */
8284 /* Input mixer1 */
Kailang Yang88102f32010-02-04 14:12:58 +01008285 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008286 /* Input mixer2 */
8287 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008288 /* Input mixer3 */
Kailang Yang88102f32010-02-04 14:12:58 +01008289 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008290 /* ADC2: mute amp left and right */
8291 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8292 /* ADC3: mute amp left and right */
8293 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8294
8295 { }
8296};
8297
8298static struct hda_verb alc885_init_input_verbs[] = {
8299 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8300 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
8301 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
8302 { }
8303};
8304
8305
8306/* Unmute Selector 24h and set the default input to front mic */
8307static struct hda_verb alc889_init_input_verbs[] = {
8308 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
8309 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8310 { }
8311};
8312
8313
Takashi Iwai4953550a2009-06-30 15:28:30 +02008314#define alc883_init_verbs alc882_base_init_verbs
8315
Tobin Davis9102cd12006-12-15 10:02:12 +01008316/* Mac Pro test */
8317static struct snd_kcontrol_new alc882_macpro_mixer[] = {
8318 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8319 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8320 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
8321 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
8322 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01008323 /* FIXME: this looks suspicious...
Jaroslav Kyselad355c82a2009-11-03 15:47:25 +01008324 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT),
8325 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01008326 */
Tobin Davis9102cd12006-12-15 10:02:12 +01008327 { } /* end */
8328};
8329
8330static struct hda_verb alc882_macpro_init_verbs[] = {
8331 /* Front mixer: unmute input/output amp left and right (volume = 0) */
8332 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8333 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8334 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8335 /* Front Pin: output 0 (0x0c) */
8336 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8337 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8338 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8339 /* Front Mic pin: input vref at 80% */
8340 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8341 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8342 /* Speaker: output */
8343 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8344 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8345 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
8346 /* Headphone output (output 0 - 0x0c) */
8347 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8348 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8349 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8350
8351 /* FIXME: use matrix-type input source selection */
8352 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8353 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8354 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8355 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8356 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8357 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8358 /* Input mixer2 */
8359 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8360 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8361 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8362 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8363 /* Input mixer3 */
8364 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8365 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8366 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8367 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8368 /* ADC1: mute amp left and right */
8369 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8370 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8371 /* ADC2: mute amp left and right */
8372 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8373 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8374 /* ADC3: mute amp left and right */
8375 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8376 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8377
8378 { }
8379};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008380
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008381/* Macbook 5,1 */
8382static struct hda_verb alc885_mb5_init_verbs[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008383 /* DACs */
8384 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8385 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8386 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8387 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008388 /* Front mixer */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008389 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8390 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8391 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008392 /* Surround mixer */
8393 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8394 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8395 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8396 /* LFE mixer */
8397 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8398 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8399 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8400 /* HP mixer */
8401 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8402 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8403 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8404 /* Front Pin (0x0c) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008405 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8406 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008407 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8408 /* LFE Pin (0x0e) */
8409 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8410 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8411 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
8412 /* HP Pin (0x0f) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008413 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8414 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008415 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
Alex Murraya76221d2010-01-13 23:15:03 +10308416 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008417 /* Front Mic pin: input vref at 80% */
8418 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8419 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8420 /* Line In pin */
8421 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8422 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8423
Alex Murrayb8f171e2010-06-14 12:08:43 +09308424 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0x1)},
8425 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x7)},
8426 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x4)},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008427 { }
8428};
8429
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008430/* Macmini 3,1 */
8431static struct hda_verb alc885_macmini3_init_verbs[] = {
8432 /* DACs */
8433 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8434 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8435 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8436 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8437 /* Front mixer */
8438 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8439 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8440 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8441 /* Surround mixer */
8442 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8443 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8444 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8445 /* LFE mixer */
8446 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8447 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8448 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8449 /* HP mixer */
8450 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8451 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8452 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8453 /* Front Pin (0x0c) */
8454 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8455 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8456 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8457 /* LFE Pin (0x0e) */
8458 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8459 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8460 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
8461 /* HP Pin (0x0f) */
8462 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8463 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8464 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
8465 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8466 /* Line In pin */
8467 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8468 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8469
8470 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8471 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8472 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8473 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8474 { }
8475};
8476
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008477
8478static struct hda_verb alc885_mba21_init_verbs[] = {
8479 /*Internal and HP Speaker Mixer*/
8480 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8481 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8482 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8483 /*Internal Speaker Pin (0x0c)*/
8484 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8485 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8486 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8487 /* HP Pin: output 0 (0x0e) */
8488 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
8489 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8490 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8491 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
8492 /* Line in (is hp when jack connected)*/
8493 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
8494 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8495
8496 { }
8497 };
8498
8499
Takashi Iwai87350ad2007-08-16 18:19:38 +02008500/* Macbook Pro rev3 */
8501static struct hda_verb alc885_mbp3_init_verbs[] = {
8502 /* Front mixer: unmute input/output amp left and right (volume = 0) */
8503 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8504 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8505 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8506 /* Rear mixer */
8507 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8508 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8509 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaia3f730af2009-08-31 08:15:26 +02008510 /* HP mixer */
8511 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8512 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8513 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai87350ad2007-08-16 18:19:38 +02008514 /* Front Pin: output 0 (0x0c) */
8515 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8516 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8517 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaia3f730af2009-08-31 08:15:26 +02008518 /* HP Pin: output 0 (0x0e) */
Takashi Iwai87350ad2007-08-16 18:19:38 +02008519 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
Takashi Iwaia3f730af2009-08-31 08:15:26 +02008520 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8521 {0x15, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai87350ad2007-08-16 18:19:38 +02008522 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8523 /* Mic (rear) pin: input vref at 80% */
8524 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8525 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8526 /* Front Mic pin: input vref at 80% */
8527 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8528 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8529 /* Line In pin: use output 1 when in LineOut mode */
8530 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8531 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8532 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
8533
8534 /* FIXME: use matrix-type input source selection */
8535 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8536 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8537 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8538 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8539 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8540 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8541 /* Input mixer2 */
8542 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8543 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8544 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8545 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8546 /* Input mixer3 */
8547 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8548 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8549 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8550 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8551 /* ADC1: mute amp left and right */
8552 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8553 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8554 /* ADC2: mute amp left and right */
8555 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8556 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8557 /* ADC3: mute amp left and right */
8558 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8559 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8560
8561 { }
8562};
8563
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008564/* iMac 9,1 */
8565static struct hda_verb alc885_imac91_init_verbs[] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008566 /* Internal Speaker Pin (0x0c) */
8567 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8568 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8569 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8570 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8571 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8572 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8573 /* HP Pin: Rear */
8574 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8575 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8576 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8577 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
8578 /* Line in Rear */
8579 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
8580 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8581 /* Front Mic pin: input vref at 80% */
8582 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8583 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008584 /* Rear mixer */
8585 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8586 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8587 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008588 /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */
8589 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8590 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8591 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8592 /* 0x24 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008593 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8594 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8595 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8596 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008597 /* 0x23 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008598 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8599 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8600 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8601 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008602 /* 0x22 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008603 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8604 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8605 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8606 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008607 /* 0x07 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008608 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8609 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008610 /* 0x08 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008611 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8612 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008613 /* 0x09 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008614 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8615 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008616 { }
8617};
8618
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008619/* iMac 24 mixer. */
8620static struct snd_kcontrol_new alc885_imac24_mixer[] = {
8621 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8622 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
8623 { } /* end */
8624};
8625
8626/* iMac 24 init verbs. */
8627static struct hda_verb alc885_imac24_init_verbs[] = {
8628 /* Internal speakers: output 0 (0x0c) */
8629 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8630 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8631 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8632 /* Internal speakers: output 0 (0x0c) */
8633 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8634 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8635 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8636 /* Headphone: output 0 (0x0c) */
8637 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8638 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8639 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8640 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8641 /* Front Mic: input vref at 80% */
8642 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8643 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8644 { }
8645};
8646
8647/* Toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008648static void alc885_imac24_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008649{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008650 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008651
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008652 spec->autocfg.hp_pins[0] = 0x14;
8653 spec->autocfg.speaker_pins[0] = 0x18;
8654 spec->autocfg.speaker_pins[1] = 0x1a;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008655}
8656
Takashi Iwai9d54f082010-02-22 08:34:40 +01008657#define alc885_mb5_setup alc885_imac24_setup
8658#define alc885_macmini3_setup alc885_imac24_setup
8659
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008660/* Macbook Air 2,1 */
8661static void alc885_mba21_setup(struct hda_codec *codec)
8662{
8663 struct alc_spec *spec = codec->spec;
8664
8665 spec->autocfg.hp_pins[0] = 0x14;
8666 spec->autocfg.speaker_pins[0] = 0x18;
8667}
8668
8669
8670
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008671static void alc885_mbp3_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008672{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008673 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008674
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008675 spec->autocfg.hp_pins[0] = 0x15;
8676 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai87350ad2007-08-16 18:19:38 +02008677}
8678
Takashi Iwai9d54f082010-02-22 08:34:40 +01008679static void alc885_imac91_setup(struct hda_codec *codec)
Alex Murraya76221d2010-01-13 23:15:03 +10308680{
Takashi Iwai9d54f082010-02-22 08:34:40 +01008681 struct alc_spec *spec = codec->spec;
Alex Murraya76221d2010-01-13 23:15:03 +10308682
Takashi Iwai9d54f082010-02-22 08:34:40 +01008683 spec->autocfg.hp_pins[0] = 0x14;
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008684 spec->autocfg.speaker_pins[0] = 0x18;
Takashi Iwai9d54f082010-02-22 08:34:40 +01008685 spec->autocfg.speaker_pins[1] = 0x1a;
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008686}
Takashi Iwai87350ad2007-08-16 18:19:38 +02008687
Kailang Yang272a5272007-05-14 11:00:38 +02008688static struct hda_verb alc882_targa_verbs[] = {
8689 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8690 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8691
8692 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8693 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008694
Kailang Yang272a5272007-05-14 11:00:38 +02008695 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8696 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8697 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8698
8699 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yang272a5272007-05-14 11:00:38 +02008700 { } /* end */
8701};
8702
8703/* toggle speaker-output according to the hp-jack state */
8704static void alc882_targa_automute(struct hda_codec *codec)
8705{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008706 struct alc_spec *spec = codec->spec;
8707 alc_automute_amp(codec);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02008708 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008709 spec->jack_present ? 1 : 3);
8710}
8711
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008712static void alc882_targa_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008713{
8714 struct alc_spec *spec = codec->spec;
8715
8716 spec->autocfg.hp_pins[0] = 0x14;
8717 spec->autocfg.speaker_pins[0] = 0x1b;
Kailang Yang272a5272007-05-14 11:00:38 +02008718}
8719
8720static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
8721{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008722 if ((res >> 26) == ALC880_HP_EVENT)
Kailang Yang272a5272007-05-14 11:00:38 +02008723 alc882_targa_automute(codec);
Kailang Yang272a5272007-05-14 11:00:38 +02008724}
8725
8726static struct hda_verb alc882_asus_a7j_verbs[] = {
8727 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8728 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8729
8730 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8731 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8732 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008733
Kailang Yang272a5272007-05-14 11:00:38 +02008734 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8735 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8736 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8737
8738 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8739 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8740 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8741 { } /* end */
8742};
8743
Takashi Iwai914759b2007-09-06 14:52:04 +02008744static struct hda_verb alc882_asus_a7m_verbs[] = {
8745 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8746 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8747
8748 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8749 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8750 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008751
Takashi Iwai914759b2007-09-06 14:52:04 +02008752 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8753 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8754 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8755
8756 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8757 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8758 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8759 { } /* end */
8760};
8761
Tobin Davis9102cd12006-12-15 10:02:12 +01008762static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
8763{
8764 unsigned int gpiostate, gpiomask, gpiodir;
8765
8766 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
8767 AC_VERB_GET_GPIO_DATA, 0);
8768
8769 if (!muted)
8770 gpiostate |= (1 << pin);
8771 else
8772 gpiostate &= ~(1 << pin);
8773
8774 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
8775 AC_VERB_GET_GPIO_MASK, 0);
8776 gpiomask |= (1 << pin);
8777
8778 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
8779 AC_VERB_GET_GPIO_DIRECTION, 0);
8780 gpiodir |= (1 << pin);
8781
8782
8783 snd_hda_codec_write(codec, codec->afg, 0,
8784 AC_VERB_SET_GPIO_MASK, gpiomask);
8785 snd_hda_codec_write(codec, codec->afg, 0,
8786 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
8787
8788 msleep(1);
8789
8790 snd_hda_codec_write(codec, codec->afg, 0,
8791 AC_VERB_SET_GPIO_DATA, gpiostate);
8792}
8793
Takashi Iwai7debbe52007-08-16 15:01:03 +02008794/* set up GPIO at initialization */
8795static void alc885_macpro_init_hook(struct hda_codec *codec)
8796{
8797 alc882_gpio_mute(codec, 0, 0);
8798 alc882_gpio_mute(codec, 1, 0);
8799}
8800
8801/* set up GPIO and update auto-muting at initialization */
8802static void alc885_imac24_init_hook(struct hda_codec *codec)
8803{
8804 alc885_macpro_init_hook(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008805 alc_automute_amp(codec);
Takashi Iwai7debbe52007-08-16 15:01:03 +02008806}
8807
Kailang Yangdf694da2005-12-05 19:42:22 +01008808/*
8809 * generic initialization of ADC, input mixers and output mixers
8810 */
Takashi Iwai4953550a2009-06-30 15:28:30 +02008811static struct hda_verb alc883_auto_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01008812 /*
8813 * Unmute ADC0-2 and set the default input to mic-in
8814 */
Kailang Yangdf694da2005-12-05 19:42:22 +01008815 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8816 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8817 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8818 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8819
Kailang Yangdf694da2005-12-05 19:42:22 +01008820 /*
8821 * Set up output mixers (0x0c - 0x0f)
8822 */
8823 /* set vol=0 to output mixers */
8824 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8825 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8826 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8827 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8828 /* set up input amps for analog loopback */
8829 /* Amp Indices: DAC = 0, mixer = 1 */
8830 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8831 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8832 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8833 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8834 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8835 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8836 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8837 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8838 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8839 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8840
8841 /* FIXME: use matrix-type input source selection */
8842 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Kailang Yangdf694da2005-12-05 19:42:22 +01008843 /* Input mixer2 */
Kailang Yang88102f32010-02-04 14:12:58 +01008844 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008845 /* Input mixer3 */
Kailang Yang88102f32010-02-04 14:12:58 +01008846 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008847 { }
8848};
8849
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008850/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
8851static struct hda_verb alc889A_mb31_ch2_init[] = {
8852 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
8853 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8854 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
8855 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
8856 { } /* end */
8857};
8858
8859/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */
8860static struct hda_verb alc889A_mb31_ch4_init[] = {
8861 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
8862 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8863 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
8864 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
8865 { } /* end */
8866};
8867
8868/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */
8869static struct hda_verb alc889A_mb31_ch5_init[] = {
8870 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */
8871 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8872 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
8873 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
8874 { } /* end */
8875};
8876
8877/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */
8878static struct hda_verb alc889A_mb31_ch6_init[] = {
8879 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */
8880 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */
8881 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
8882 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
8883 { } /* end */
8884};
8885
8886static struct hda_channel_mode alc889A_mb31_6ch_modes[4] = {
8887 { 2, alc889A_mb31_ch2_init },
8888 { 4, alc889A_mb31_ch4_init },
8889 { 5, alc889A_mb31_ch5_init },
8890 { 6, alc889A_mb31_ch6_init },
8891};
8892
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008893static struct hda_verb alc883_medion_eapd_verbs[] = {
8894 /* eanable EAPD on medion laptop */
8895 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8896 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
8897 { }
8898};
8899
Takashi Iwai4953550a2009-06-30 15:28:30 +02008900#define alc883_base_mixer alc882_base_mixer
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008901
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008902static struct snd_kcontrol_new alc883_mitac_mixer[] = {
8903 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8904 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8905 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8906 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8907 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8908 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8909 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8910 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008911 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008912 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8913 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008914 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008915 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008916 { } /* end */
8917};
8918
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008919static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01008920 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8921 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8922 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8923 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8924 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008925 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01008926 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01008927 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008928 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01008929 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01008930 { } /* end */
8931};
8932
Jiang zhefb97dc62008-03-06 11:07:11 +01008933static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
8934 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8935 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8936 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8937 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8938 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008939 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01008940 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01008941 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008942 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01008943 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01008944 { } /* end */
8945};
8946
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008947static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
8948 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8949 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8950 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8951 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8952 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8953 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8954 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8955 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008956 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008957 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8958 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008959 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008960 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008961 { } /* end */
8962};
8963
8964static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
8965 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8966 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8967 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8968 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8969 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8970 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8971 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8972 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8973 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8974 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8975 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8976 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8977 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8978 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008979 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008980 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8981 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008982 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008983 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008984 { } /* end */
8985};
8986
Jiang zhe17bba1b2008-06-04 12:11:07 +02008987static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
8988 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8989 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8990 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8991 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8992 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
8993 HDA_OUTPUT),
8994 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8995 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8996 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8997 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8998 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8999 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9000 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9001 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9002 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009003 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02009004 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
9005 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009006 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02009007 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02009008 { } /* end */
9009};
9010
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009011static struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
9012 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9013 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9014 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9015 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
9016 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
9017 HDA_OUTPUT),
9018 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
9019 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9020 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
9021 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
9022 HDA_BIND_MUTE("Speaker Playback Switch", 0x0f, 2, HDA_INPUT),
9023 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9024 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9025 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9026 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009027 HDA_CODEC_VOLUME("Mic Boost Volume", 0x1b, 0, HDA_INPUT),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009028 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
9029 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009030 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009031 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9032 { } /* end */
9033};
9034
Takashi Iwaid1d985f2006-11-23 19:27:12 +01009035static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02009036 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02009037 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009038 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02009039 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009040 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
9041 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02009042 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9043 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009044 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9045 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9046 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9047 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9048 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9049 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009050 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009051 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9052 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009053 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009054 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009055 { } /* end */
9056};
9057
Sasha Alexandrc2592492009-06-16 14:52:54 -04009058static struct snd_kcontrol_new alc883_targa_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02009059 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009060 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009061 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009062 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009063 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9064 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
9065 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
9066 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
9067 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9068 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
9069 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9070 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9071 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9072 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9073 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009074 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009075 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009076 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009077};
Kailang Yangccc656c2006-10-17 12:32:26 +02009078
Sasha Alexandrc2592492009-06-16 14:52:54 -04009079static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02009080 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009081 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009082 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009083 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009084 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9085 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9086 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009087 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009088 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009089 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009090 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009091 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009092 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009093};
Kailang Yangccc656c2006-10-17 12:32:26 +02009094
Takashi Iwaib99dba32009-09-17 18:23:00 +02009095static struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
9096 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
9097 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009098 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009099 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009100 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009101 { } /* end */
9102};
9103
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009104static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
9105 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9106 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01009107 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9108 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009109 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9110 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009111 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009112 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009113 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009114};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009115
Kailang Yang272a5272007-05-14 11:00:38 +02009116static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
9117 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9118 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
9119 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9120 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9121 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9122 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9123 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009124 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
9125 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02009126 { } /* end */
Kailang Yangea1fb292008-08-26 12:58:38 +02009127};
Kailang Yang272a5272007-05-14 11:00:38 +02009128
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009129static struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = {
9130 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9131 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9132 HDA_CODEC_MUTE("Speaker Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9133 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
9134 HDA_CODEC_VOLUME("Line Playback Volume", 0x08, 0x0, HDA_INPUT),
9135 HDA_CODEC_MUTE("Line Playback Switch", 0x08, 0x0, HDA_INPUT),
9136 { } /* end */
9137};
9138
9139static struct hda_verb alc883_medion_wim2160_verbs[] = {
9140 /* Unmute front mixer */
9141 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9142 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9143
9144 /* Set speaker pin to front mixer */
9145 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9146
9147 /* Init headphone pin */
9148 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9149 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9150 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
9151 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9152
9153 { } /* end */
9154};
9155
9156/* toggle speaker-output according to the hp-jack state */
9157static void alc883_medion_wim2160_setup(struct hda_codec *codec)
9158{
9159 struct alc_spec *spec = codec->spec;
9160
9161 spec->autocfg.hp_pins[0] = 0x1a;
9162 spec->autocfg.speaker_pins[0] = 0x15;
9163}
9164
Tobin Davis2880a862007-08-07 11:50:26 +02009165static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02009166 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9167 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02009168 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02009169 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9170 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02009171 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009172 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02009173 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02009174 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02009175};
Tobin Davis2880a862007-08-07 11:50:26 +02009176
Tony Vroond2fd4b02009-06-21 00:40:10 +01009177static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
9178 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01009179 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Tony Vroon684a8842009-06-26 09:27:50 +01009180 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9181 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01009182 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9183 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, 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),
Tony Vroond2fd4b02009-06-21 00:40:10 +01009186 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9187 { } /* end */
9188};
9189
Kailang Yange2757d52008-08-26 13:17:46 +02009190static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
9191 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9192 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9193 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
9194 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
9195 HDA_CODEC_VOLUME_MONO("Center Playback Volume",
9196 0x0d, 1, 0x0, HDA_OUTPUT),
9197 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
9198 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
9199 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
9200 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
9201 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009202 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9203 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9204 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9205 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9206 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009207 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009208 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9209 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009210 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009211 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009212 { } /* end */
9213};
9214
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009215static struct snd_kcontrol_new alc889A_mb31_mixer[] = {
9216 /* Output mixers */
9217 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
9218 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
9219 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
9220 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
9221 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00,
9222 HDA_OUTPUT),
9223 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT),
9224 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT),
9225 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT),
9226 /* Output switches */
9227 HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT),
9228 HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT),
9229 HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT),
9230 /* Boost mixers */
David Henningsson5f99f862011-01-04 15:24:24 +01009231 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT),
9232 HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT),
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009233 /* Input mixers */
9234 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
9235 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
9236 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9237 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9238 { } /* end */
9239};
9240
Guido Günther3e1647c52009-06-05 00:47:26 +02009241static struct snd_kcontrol_new alc883_vaiott_mixer[] = {
9242 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9243 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9244 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9245 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009246 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
Guido Günther3e1647c52009-06-05 00:47:26 +02009247 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
9248 { } /* end */
9249};
9250
Kailang Yange2757d52008-08-26 13:17:46 +02009251static struct hda_bind_ctls alc883_bind_cap_vol = {
9252 .ops = &snd_hda_bind_vol,
9253 .values = {
9254 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
9255 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
9256 0
9257 },
9258};
9259
9260static struct hda_bind_ctls alc883_bind_cap_switch = {
9261 .ops = &snd_hda_bind_sw,
9262 .values = {
9263 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
9264 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
9265 0
9266 },
9267};
9268
9269static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
9270 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9271 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9272 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9273 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9274 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9275 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009276 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009277 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009278 { } /* end */
9279};
9280
9281static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009282 HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
9283 HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
9284 {
9285 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9286 /* .name = "Capture Source", */
9287 .name = "Input Source",
9288 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01009289 .info = alc_mux_enum_info,
9290 .get = alc_mux_enum_get,
9291 .put = alc_mux_enum_put,
Kailang Yange2757d52008-08-26 13:17:46 +02009292 },
9293 { } /* end */
9294};
9295
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009296static struct snd_kcontrol_new alc883_chmode_mixer[] = {
9297 {
9298 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9299 .name = "Channel Mode",
9300 .info = alc_ch_mode_info,
9301 .get = alc_ch_mode_get,
9302 .put = alc_ch_mode_put,
9303 },
9304 { } /* end */
9305};
9306
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009307/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009308static void alc883_mitac_setup(struct hda_codec *codec)
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009309{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009310 struct alc_spec *spec = codec->spec;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009311
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009312 spec->autocfg.hp_pins[0] = 0x15;
9313 spec->autocfg.speaker_pins[0] = 0x14;
9314 spec->autocfg.speaker_pins[1] = 0x17;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009315}
9316
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009317static struct hda_verb alc883_mitac_verbs[] = {
9318 /* HP */
9319 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9320 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9321 /* Subwoofer */
9322 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
9323 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9324
9325 /* enable unsolicited event */
9326 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9327 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
9328
9329 { } /* end */
9330};
9331
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309332static struct hda_verb alc883_clevo_m540r_verbs[] = {
9333 /* HP */
9334 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9335 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9336 /* Int speaker */
9337 /*{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},*/
9338
9339 /* enable unsolicited event */
9340 /*
9341 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9342 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
9343 */
9344
9345 { } /* end */
9346};
9347
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009348static struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01009349 /* HP */
9350 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9351 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9352 /* Int speaker */
9353 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
9354 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9355
9356 /* enable unsolicited event */
9357 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009358 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01009359
9360 { } /* end */
9361};
9362
Jiang zhefb97dc62008-03-06 11:07:11 +01009363static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
9364 /* HP */
9365 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9366 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9367 /* Subwoofer */
9368 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
9369 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9370
9371 /* enable unsolicited event */
9372 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9373
9374 { } /* end */
9375};
9376
Sasha Alexandrc2592492009-06-16 14:52:54 -04009377static struct hda_verb alc883_targa_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02009378 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9379 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9380
9381 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9382 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02009383
David Heidelberger64a8be72009-06-08 16:15:18 +02009384/* Connect Line-Out side jack (SPDIF) to Side */
9385 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9386 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9387 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
9388/* Connect Mic jack to CLFE */
9389 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9390 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9391 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
9392/* Connect Line-in jack to Surround */
9393 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9394 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9395 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
9396/* Connect HP out jack to Front */
9397 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9398 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9399 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangccc656c2006-10-17 12:32:26 +02009400
9401 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangccc656c2006-10-17 12:32:26 +02009402
9403 { } /* end */
9404};
9405
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009406static struct hda_verb alc883_lenovo_101e_verbs[] = {
9407 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9408 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
9409 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
9410 { } /* end */
9411};
9412
Kailang Yang272a5272007-05-14 11:00:38 +02009413static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
9414 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9415 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9416 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9417 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9418 { } /* end */
9419};
9420
9421static struct hda_verb alc888_lenovo_ms7195_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 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9425 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
9426 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9427 { } /* end */
9428};
9429
Kailang Yang189609a2007-08-20 11:31:23 +02009430static struct hda_verb alc883_haier_w66_verbs[] = {
9431 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9432 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9433
9434 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9435
9436 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9437 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9438 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9439 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9440 { } /* end */
9441};
9442
Kailang Yange2757d52008-08-26 13:17:46 +02009443static struct hda_verb alc888_lenovo_sky_verbs[] = {
9444 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9445 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9446 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9447 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9448 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9449 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9450 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
9451 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9452 { } /* end */
9453};
9454
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009455static struct hda_verb alc888_6st_dell_verbs[] = {
9456 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9457 { }
9458};
9459
Guido Günther3e1647c52009-06-05 00:47:26 +02009460static struct hda_verb alc883_vaiott_verbs[] = {
9461 /* HP */
9462 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9463 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9464
9465 /* enable unsolicited event */
9466 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9467
9468 { } /* end */
9469};
9470
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009471static void alc888_3st_hp_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009472{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009473 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009474
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009475 spec->autocfg.hp_pins[0] = 0x1b;
9476 spec->autocfg.speaker_pins[0] = 0x14;
9477 spec->autocfg.speaker_pins[1] = 0x16;
9478 spec->autocfg.speaker_pins[2] = 0x18;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009479}
9480
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009481static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009482 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01009483 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
9484 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009485 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009486 { } /* end */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009487};
9488
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009489/*
9490 * 2ch mode
9491 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009492static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009493 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9494 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9495 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
9496 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009497 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009498};
9499
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009500/*
9501 * 4ch mode
9502 */
9503static struct hda_verb alc888_3st_hp_4ch_init[] = {
9504 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9505 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9506 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9507 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9508 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
9509 { } /* end */
9510};
9511
9512/*
9513 * 6ch mode
9514 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009515static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009516 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9517 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009518 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009519 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9520 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009521 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
9522 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009523};
9524
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009525static struct hda_channel_mode alc888_3st_hp_modes[3] = {
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009526 { 2, alc888_3st_hp_2ch_init },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009527 { 4, alc888_3st_hp_4ch_init },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009528 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009529};
9530
Kailang Yang272a5272007-05-14 11:00:38 +02009531/* toggle front-jack and RCA according to the hp-jack state */
9532static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
9533{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009534 unsigned int present = snd_hda_jack_detect(codec, 0x1b);
Kailang Yangea1fb292008-08-26 12:58:38 +02009535
Takashi Iwai47fd8302007-08-10 17:11:07 +02009536 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9537 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9538 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9539 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02009540}
9541
9542/* toggle RCA according to the front-jack state */
9543static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
9544{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009545 unsigned int present = snd_hda_jack_detect(codec, 0x14);
Kailang Yangea1fb292008-08-26 12:58:38 +02009546
Takashi Iwai47fd8302007-08-10 17:11:07 +02009547 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9548 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02009549}
Takashi Iwai47fd8302007-08-10 17:11:07 +02009550
Kailang Yang272a5272007-05-14 11:00:38 +02009551static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
9552 unsigned int res)
9553{
9554 if ((res >> 26) == ALC880_HP_EVENT)
9555 alc888_lenovo_ms7195_front_automute(codec);
9556 if ((res >> 26) == ALC880_FRONT_EVENT)
9557 alc888_lenovo_ms7195_rca_automute(codec);
9558}
9559
Kailang Yang272a5272007-05-14 11:00:38 +02009560/* toggle speaker-output according to the hp-jack state */
Takashi Iwaidc4271702010-11-29 07:42:59 +01009561static void alc883_lenovo_nb0763_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +02009562{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009563 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009564
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009565 spec->autocfg.hp_pins[0] = 0x14;
9566 spec->autocfg.speaker_pins[0] = 0x15;
Kailang Yang272a5272007-05-14 11:00:38 +02009567}
9568
Kailang Yangccc656c2006-10-17 12:32:26 +02009569/* toggle speaker-output according to the hp-jack state */
Sasha Alexandrc2592492009-06-16 14:52:54 -04009570#define alc883_targa_init_hook alc882_targa_init_hook
9571#define alc883_targa_unsol_event alc882_targa_unsol_event
Jiang zhe368c7a92008-03-04 11:20:33 +01009572
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009573static void alc883_clevo_m720_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009574{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009575 struct alc_spec *spec = codec->spec;
9576
9577 spec->autocfg.hp_pins[0] = 0x15;
9578 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009579}
9580
9581static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
9582{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009583 alc_automute_amp(codec);
Anisse Astiereeb43382010-12-16 12:19:47 +01009584 alc88x_simple_mic_automute(codec);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009585}
9586
9587static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01009588 unsigned int res)
9589{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009590 switch (res >> 26) {
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009591 case ALC880_MIC_EVENT:
Anisse Astiereeb43382010-12-16 12:19:47 +01009592 alc88x_simple_mic_automute(codec);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009593 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009594 default:
9595 alc_automute_amp_unsol_event(codec, res);
9596 break;
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009597 }
Jiang zhe368c7a92008-03-04 11:20:33 +01009598}
9599
Jiang zhefb97dc62008-03-06 11:07:11 +01009600/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009601static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01009602{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009603 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01009604
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009605 spec->autocfg.hp_pins[0] = 0x14;
9606 spec->autocfg.speaker_pins[0] = 0x15;
Jiang zhefb97dc62008-03-06 11:07:11 +01009607}
9608
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009609static void alc883_haier_w66_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01009610{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009611 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01009612
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009613 spec->autocfg.hp_pins[0] = 0x1b;
9614 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang189609a2007-08-20 11:31:23 +02009615}
9616
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009617static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
9618{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009619 int bits = snd_hda_jack_detect(codec, 0x14) ? HDA_AMP_MUTE : 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009620
Takashi Iwai47fd8302007-08-10 17:11:07 +02009621 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9622 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009623}
9624
9625static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
9626{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009627 int bits = snd_hda_jack_detect(codec, 0x1b) ? HDA_AMP_MUTE : 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009628
Takashi Iwai47fd8302007-08-10 17:11:07 +02009629 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9630 HDA_AMP_MUTE, bits);
9631 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9632 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009633}
9634
9635static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
9636 unsigned int res)
9637{
9638 if ((res >> 26) == ALC880_HP_EVENT)
9639 alc883_lenovo_101e_all_automute(codec);
9640 if ((res >> 26) == ALC880_FRONT_EVENT)
9641 alc883_lenovo_101e_ispeaker_automute(codec);
9642}
9643
Takashi Iwai676a9b52007-08-16 15:23:35 +02009644/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009645static void alc883_acer_aspire_setup(struct hda_codec *codec)
Takashi Iwai676a9b52007-08-16 15:23:35 +02009646{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009647 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009648
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009649 spec->autocfg.hp_pins[0] = 0x14;
9650 spec->autocfg.speaker_pins[0] = 0x15;
9651 spec->autocfg.speaker_pins[1] = 0x16;
Takashi Iwai676a9b52007-08-16 15:23:35 +02009652}
9653
Kailang Yangd1a991a2007-08-15 16:21:59 +02009654static struct hda_verb alc883_acer_eapd_verbs[] = {
9655 /* HP Pin: output 0 (0x0c) */
9656 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9657 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9658 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9659 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02009660 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9661 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009662 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009663 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
9664 /* eanable EAPD on medion laptop */
9665 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
9666 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02009667 /* enable unsolicited event */
9668 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009669 { }
9670};
9671
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009672static void alc888_6st_dell_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009673{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009674 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009675
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009676 spec->autocfg.hp_pins[0] = 0x1b;
9677 spec->autocfg.speaker_pins[0] = 0x14;
9678 spec->autocfg.speaker_pins[1] = 0x15;
9679 spec->autocfg.speaker_pins[2] = 0x16;
9680 spec->autocfg.speaker_pins[3] = 0x17;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009681}
9682
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009683static void alc888_lenovo_sky_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009684{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009685 struct alc_spec *spec = codec->spec;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009686
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009687 spec->autocfg.hp_pins[0] = 0x1b;
9688 spec->autocfg.speaker_pins[0] = 0x14;
9689 spec->autocfg.speaker_pins[1] = 0x15;
9690 spec->autocfg.speaker_pins[2] = 0x16;
9691 spec->autocfg.speaker_pins[3] = 0x17;
9692 spec->autocfg.speaker_pins[4] = 0x1a;
Kailang Yange2757d52008-08-26 13:17:46 +02009693}
9694
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009695static void alc883_vaiott_setup(struct hda_codec *codec)
Guido Günther3e1647c52009-06-05 00:47:26 +02009696{
9697 struct alc_spec *spec = codec->spec;
9698
9699 spec->autocfg.hp_pins[0] = 0x15;
9700 spec->autocfg.speaker_pins[0] = 0x14;
9701 spec->autocfg.speaker_pins[1] = 0x17;
Guido Günther3e1647c52009-06-05 00:47:26 +02009702}
9703
Kailang Yange2757d52008-08-26 13:17:46 +02009704static struct hda_verb alc888_asus_m90v_verbs[] = {
9705 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9706 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9707 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9708 /* enable unsolicited event */
9709 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9710 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
9711 { } /* end */
9712};
9713
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009714static void alc883_mode2_setup(struct hda_codec *codec)
Kailang Yange2757d52008-08-26 13:17:46 +02009715{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009716 struct alc_spec *spec = codec->spec;
Kailang Yange2757d52008-08-26 13:17:46 +02009717
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009718 spec->autocfg.hp_pins[0] = 0x1b;
9719 spec->autocfg.speaker_pins[0] = 0x14;
9720 spec->autocfg.speaker_pins[1] = 0x15;
9721 spec->autocfg.speaker_pins[2] = 0x16;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009722 spec->ext_mic.pin = 0x18;
9723 spec->int_mic.pin = 0x19;
9724 spec->ext_mic.mux_idx = 0;
9725 spec->int_mic.mux_idx = 1;
9726 spec->auto_mic = 1;
Kailang Yange2757d52008-08-26 13:17:46 +02009727}
9728
9729static struct hda_verb alc888_asus_eee1601_verbs[] = {
9730 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9731 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9732 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9733 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9734 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9735 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
9736 {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
9737 /* enable unsolicited event */
9738 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9739 { } /* end */
9740};
9741
Kailang Yange2757d52008-08-26 13:17:46 +02009742static void alc883_eee1601_inithook(struct hda_codec *codec)
9743{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009744 struct alc_spec *spec = codec->spec;
9745
9746 spec->autocfg.hp_pins[0] = 0x14;
9747 spec->autocfg.speaker_pins[0] = 0x1b;
9748 alc_automute_pin(codec);
Kailang Yange2757d52008-08-26 13:17:46 +02009749}
9750
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009751static struct hda_verb alc889A_mb31_verbs[] = {
9752 /* Init rear pin (used as headphone output) */
9753 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */
9754 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */
9755 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9756 /* Init line pin (used as output in 4ch and 6ch mode) */
9757 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Connect to CLFE */
9758 /* Init line 2 pin (used as headphone out by default) */
9759 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Use as input */
9760 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */
9761 { } /* end */
9762};
9763
9764/* Mute speakers according to the headphone jack state */
9765static void alc889A_mb31_automute(struct hda_codec *codec)
9766{
9767 unsigned int present;
9768
9769 /* Mute only in 2ch or 4ch mode */
9770 if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0)
9771 == 0x00) {
Wu Fengguang864f92b2009-11-18 12:38:02 +08009772 present = snd_hda_jack_detect(codec, 0x15);
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009773 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9774 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9775 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
9776 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9777 }
9778}
9779
9780static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
9781{
9782 if ((res >> 26) == ALC880_HP_EVENT)
9783 alc889A_mb31_automute(codec);
9784}
9785
Takashi Iwai4953550a2009-06-30 15:28:30 +02009786
Takashi Iwaicb53c622007-08-10 17:21:45 +02009787#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwai4953550a2009-06-30 15:28:30 +02009788#define alc882_loopbacks alc880_loopbacks
Takashi Iwaicb53c622007-08-10 17:21:45 +02009789#endif
9790
Sasha Alexandrdef319f2009-06-16 16:00:15 -04009791/* pcm configuration: identical with ALC880 */
Takashi Iwai4953550a2009-06-30 15:28:30 +02009792#define alc882_pcm_analog_playback alc880_pcm_analog_playback
9793#define alc882_pcm_analog_capture alc880_pcm_analog_capture
9794#define alc882_pcm_digital_playback alc880_pcm_digital_playback
9795#define alc882_pcm_digital_capture alc880_pcm_digital_capture
9796
9797static hda_nid_t alc883_slave_dig_outs[] = {
9798 ALC1200_DIGOUT_NID, 0,
9799};
9800
9801static hda_nid_t alc1200_slave_dig_outs[] = {
9802 ALC883_DIGOUT_NID, 0,
9803};
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009804
9805/*
9806 * configuration and preset
9807 */
Takashi Iwaiea734962011-01-17 11:29:34 +01009808static const char * const alc882_models[ALC882_MODEL_LAST] = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02009809 [ALC882_3ST_DIG] = "3stack-dig",
9810 [ALC882_6ST_DIG] = "6stack-dig",
9811 [ALC882_ARIMA] = "arima",
9812 [ALC882_W2JC] = "w2jc",
9813 [ALC882_TARGA] = "targa",
9814 [ALC882_ASUS_A7J] = "asus-a7j",
9815 [ALC882_ASUS_A7M] = "asus-a7m",
9816 [ALC885_MACPRO] = "macpro",
9817 [ALC885_MB5] = "mb5",
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009818 [ALC885_MACMINI3] = "macmini3",
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08009819 [ALC885_MBA21] = "mba21",
Takashi Iwai4953550a2009-06-30 15:28:30 +02009820 [ALC885_MBP3] = "mbp3",
9821 [ALC885_IMAC24] = "imac24",
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009822 [ALC885_IMAC91] = "imac91",
Takashi Iwai4953550a2009-06-30 15:28:30 +02009823 [ALC883_3ST_2ch_DIG] = "3stack-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009824 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
9825 [ALC883_3ST_6ch] = "3stack-6ch",
Takashi Iwai4953550a2009-06-30 15:28:30 +02009826 [ALC883_6ST_DIG] = "alc883-6stack-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009827 [ALC883_TARGA_DIG] = "targa-dig",
9828 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
David Heidelberger64a8be72009-06-08 16:15:18 +02009829 [ALC883_TARGA_8ch_DIG] = "targa-8ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009830 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02009831 [ALC883_ACER_ASPIRE] = "acer-aspire",
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009832 [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g",
Takashi Iwaib1a91462009-06-21 10:56:44 +02009833 [ALC888_ACER_ASPIRE_6530G] = "acer-aspire-6530g",
Hector Martin3b315d72009-06-02 10:54:19 +02009834 [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g",
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009835 [ALC888_ACER_ASPIRE_7730G] = "acer-aspire-7730g",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009836 [ALC883_MEDION] = "medion",
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009837 [ALC883_MEDION_WIM2160] = "medion-wim2160",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009838 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009839 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02009840 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
9841 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yange2757d52008-08-26 13:17:46 +02009842 [ALC888_LENOVO_SKY] = "lenovo-sky",
Kailang Yang189609a2007-08-20 11:31:23 +02009843 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009844 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009845 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009846 [ALC883_MITAC] = "mitac",
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309847 [ALC883_CLEVO_M540R] = "clevo-m540r",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009848 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +01009849 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009850 [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
Jiang zhe17bba1b2008-06-04 12:11:07 +02009851 [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009852 [ALC889A_INTEL] = "intel-alc889a",
9853 [ALC889_INTEL] = "intel-x58",
Wu Fengguang3ab90932008-11-17 09:51:09 +01009854 [ALC1200_ASUS_P5Q] = "asus-p5q",
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009855 [ALC889A_MB31] = "mb31",
Guido Günther3e1647c52009-06-05 00:47:26 +02009856 [ALC883_SONY_VAIO_TT] = "sony-vaio-tt",
Takashi Iwai4953550a2009-06-30 15:28:30 +02009857 [ALC882_AUTO] = "auto",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009858};
9859
Takashi Iwai4953550a2009-06-30 15:28:30 +02009860static struct snd_pci_quirk alc882_cfg_tbl[] = {
9861 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
9862
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009863 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
Takashi Iwai69e50282008-11-03 10:07:43 +01009864 SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
Takashi Iwai9b6682f2009-03-23 22:50:52 +01009865 SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009866 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
9867 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
Jaroslav Kysela0b18cb12008-07-28 17:07:07 +02009868 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009869 SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
9870 ALC888_ACER_ASPIRE_4930G),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01009871 SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
Takashi Iwai83dd7402009-11-24 08:57:53 +01009872 ALC888_ACER_ASPIRE_4930G),
Hector Martin3b315d72009-06-02 10:54:19 +02009873 SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
9874 ALC888_ACER_ASPIRE_8930G),
Takashi Iwaie46b0c82009-06-13 10:16:43 +02009875 SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
9876 ALC888_ACER_ASPIRE_8930G),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009877 SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO),
9878 SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01009879 SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
Takashi Iwaidde65352009-06-25 08:25:35 +02009880 ALC888_ACER_ASPIRE_6530G),
Juan Jesus Garcia de Soriacc374c42009-02-23 08:11:59 +01009881 SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
Tony Vroond2fd4b02009-06-21 00:40:10 +01009882 ALC888_ACER_ASPIRE_6530G),
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009883 SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
9884 ALC888_ACER_ASPIRE_7730G),
Takashi Iwai22b530e2009-05-13 11:32:52 +02009885 /* default Acer -- disabled as it causes more problems.
9886 * model=auto should work fine now
9887 */
9888 /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */
Takashi Iwai4953550a2009-06-30 15:28:30 +02009889
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009890 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009891
Tobin Davisfebe3372007-06-12 11:27:46 +02009892 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009893 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
9894 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +01009895 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Chris Bagwell06bf3e12009-01-01 10:32:08 +01009896 SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
Herton Ronaldo Krzesinski7ec30f02009-03-04 14:22:52 -03009897 SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009898
9899 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
9900 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
9901 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Kailang Yanga01c30c2008-10-15 11:14:58 +02009902 SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009903 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
9904 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
9905 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009906 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Mackenzie Morgan44a678d2009-02-10 17:13:43 +01009907 SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
Wu Fengguang3ab90932008-11-17 09:51:09 +01009908 SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
Kailang Yange2757d52008-08-26 13:17:46 +02009909 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009910
9911 SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
Travis Place97ec7102008-05-23 18:31:46 +02009912 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009913 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009914 SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009915 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
9916 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
Kailang Yange2757d52008-08-26 13:17:46 +02009917 SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009918 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009919 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
9920
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009921 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
9922 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
9923 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009924 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
Takashi Iwai2fef62c2009-12-18 08:48:42 +01009925 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC882_AUTO),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009926 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009927 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01009928 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009929 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
9930 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
9931 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
9932 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
9933 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
9934 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009935 SND_PCI_QUIRK(0x1462, 0x42cd, "MSI", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009936 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
9937 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
9938 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Anisse Astierb43f6e52010-03-10 19:17:46 +01009939 SND_PCI_QUIRK(0x1462, 0x4570, "MSI Wind Top AE2220", ALC883_TARGA_DIG),
David Heidelberger64a8be72009-06-08 16:15:18 +02009940 SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009941 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
9942 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02009943 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Takashi Iwaiee095432008-11-25 15:03:38 +01009944 SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +01009945 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01009946 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02009947 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Sasha Alexandrdf01b8a2009-06-16 14:46:17 -04009948 SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG),
Anisse Astierb43f6e52010-03-10 19:17:46 +01009949 SND_PCI_QUIRK(0x1462, 0x7437, "MSI NetOn AP1900", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009950 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009951 SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009952
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009953 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Joerg Schirottked1501ea2010-04-15 08:37:41 +02009954 SND_PCI_QUIRK(0x1558, 0x0571, "Clevo laptop M570U", ALC883_3ST_6ch_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009955 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
9956 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309957 SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R),
Takashi Iwaidea0a502009-02-09 17:14:52 +01009958 SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04009959 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009960 /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009961 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009962 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
Takashi Iwaif67d8172009-02-04 23:30:19 +01009963 ALC883_FUJITSU_PI2515),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009964 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009965 ALC888_FUJITSU_XA3530),
Kailang Yang272a5272007-05-14 11:00:38 +02009966 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02009967 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009968 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
9969 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yange2757d52008-08-26 13:17:46 +02009970 SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
Takashi Iwai959973b2008-11-05 11:30:56 +01009971 SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01009972 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02009973 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009974
Jiang zhe17bba1b2008-06-04 12:11:07 +02009975 SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
9976 SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009977 SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009978 SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL),
9979 SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL),
9980 SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL),
Daniel T Chen572c0e32010-03-14 23:44:03 -04009981 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC882_6ST_DIG),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009982
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009983 {}
9984};
9985
Takashi Iwai4953550a2009-06-30 15:28:30 +02009986/* codec SSID table for Intel Mac */
9987static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
9988 SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3),
9989 SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3),
9990 SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3),
9991 SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO),
9992 SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24),
9993 SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24),
9994 SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3),
Daniel T Chen26fd74f2010-05-30 09:55:23 -04009995 SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31),
Justin P. Mattockab669962010-06-06 16:09:53 -07009996 SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_ASUS_A7M),
Justin P. Mattockf53dae22010-06-06 16:09:51 -07009997 SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC885_MBP3),
Justin P. Mattock6e129702010-06-06 16:09:49 -07009998 SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC885_MBA21),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009999 SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
10000 SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
10001 SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010002 SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91),
Takashi Iwai4953550a2009-06-30 15:28:30 +020010003 SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5),
Luke Yelavich3bfea982010-06-22 11:04:19 +100010004 SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -050010005 /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2,
10006 * so apparently no perfect solution yet
Takashi Iwai4953550a2009-06-30 15:28:30 +020010007 */
10008 SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -050010009 SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5),
Luke Yelaviche458b1f2010-02-12 16:28:29 +110010010 SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC885_MACMINI3),
Takashi Iwai4953550a2009-06-30 15:28:30 +020010011 {} /* terminator */
Wu Fengguangf3cd3f52009-04-02 19:44:18 +080010012};
10013
Takashi Iwai4953550a2009-06-30 15:28:30 +020010014static struct alc_config_preset alc882_presets[] = {
10015 [ALC882_3ST_DIG] = {
10016 .mixers = { alc882_base_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010017 .init_verbs = { alc882_base_init_verbs,
10018 alc882_adc1_init_verbs },
Takashi Iwai4953550a2009-06-30 15:28:30 +020010019 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10020 .dac_nids = alc882_dac_nids,
10021 .dig_out_nid = ALC882_DIGOUT_NID,
10022 .dig_in_nid = ALC882_DIGIN_NID,
10023 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
10024 .channel_mode = alc882_ch_modes,
10025 .need_dac_fix = 1,
10026 .input_mux = &alc882_capture_source,
10027 },
10028 [ALC882_6ST_DIG] = {
10029 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010030 .init_verbs = { alc882_base_init_verbs,
10031 alc882_adc1_init_verbs },
Takashi Iwai4953550a2009-06-30 15:28:30 +020010032 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10033 .dac_nids = alc882_dac_nids,
10034 .dig_out_nid = ALC882_DIGOUT_NID,
10035 .dig_in_nid = ALC882_DIGIN_NID,
10036 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
10037 .channel_mode = alc882_sixstack_modes,
10038 .input_mux = &alc882_capture_source,
10039 },
10040 [ALC882_ARIMA] = {
10041 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010042 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10043 alc882_eapd_verbs },
Takashi Iwai4953550a2009-06-30 15:28:30 +020010044 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10045 .dac_nids = alc882_dac_nids,
10046 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
10047 .channel_mode = alc882_sixstack_modes,
10048 .input_mux = &alc882_capture_source,
10049 },
10050 [ALC882_W2JC] = {
10051 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010052 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10053 alc882_eapd_verbs, alc880_gpio1_init_verbs },
Takashi Iwai4953550a2009-06-30 15:28:30 +020010054 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10055 .dac_nids = alc882_dac_nids,
10056 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
10057 .channel_mode = alc880_threestack_modes,
10058 .need_dac_fix = 1,
10059 .input_mux = &alc882_capture_source,
10060 .dig_out_nid = ALC882_DIGOUT_NID,
10061 },
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -080010062 [ALC885_MBA21] = {
10063 .mixers = { alc885_mba21_mixer },
10064 .init_verbs = { alc885_mba21_init_verbs, alc880_gpio1_init_verbs },
10065 .num_dacs = 2,
10066 .dac_nids = alc882_dac_nids,
10067 .channel_mode = alc885_mba21_ch_modes,
10068 .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
10069 .input_mux = &alc882_capture_source,
10070 .unsol_event = alc_automute_amp_unsol_event,
10071 .setup = alc885_mba21_setup,
10072 .init_hook = alc_automute_amp,
10073 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020010074 [ALC885_MBP3] = {
10075 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
10076 .init_verbs = { alc885_mbp3_init_verbs,
10077 alc880_gpio1_init_verbs },
Takashi Iwaibe0ae922009-08-31 08:27:10 +020010078 .num_dacs = 2,
Takashi Iwai4953550a2009-06-30 15:28:30 +020010079 .dac_nids = alc882_dac_nids,
Takashi Iwaibe0ae922009-08-31 08:27:10 +020010080 .hp_nid = 0x04,
10081 .channel_mode = alc885_mbp_4ch_modes,
10082 .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes),
Takashi Iwai4953550a2009-06-30 15:28:30 +020010083 .input_mux = &alc882_capture_source,
10084 .dig_out_nid = ALC882_DIGOUT_NID,
10085 .dig_in_nid = ALC882_DIGIN_NID,
10086 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010087 .setup = alc885_mbp3_setup,
10088 .init_hook = alc_automute_amp,
Takashi Iwai4953550a2009-06-30 15:28:30 +020010089 },
10090 [ALC885_MB5] = {
10091 .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
10092 .init_verbs = { alc885_mb5_init_verbs,
10093 alc880_gpio1_init_verbs },
10094 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10095 .dac_nids = alc882_dac_nids,
10096 .channel_mode = alc885_mb5_6ch_modes,
10097 .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
10098 .input_mux = &mb5_capture_source,
10099 .dig_out_nid = ALC882_DIGOUT_NID,
10100 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +010010101 .unsol_event = alc_automute_amp_unsol_event,
10102 .setup = alc885_mb5_setup,
10103 .init_hook = alc_automute_amp,
Takashi Iwai4953550a2009-06-30 15:28:30 +020010104 },
Luke Yelaviche458b1f2010-02-12 16:28:29 +110010105 [ALC885_MACMINI3] = {
10106 .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer },
10107 .init_verbs = { alc885_macmini3_init_verbs,
10108 alc880_gpio1_init_verbs },
10109 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10110 .dac_nids = alc882_dac_nids,
10111 .channel_mode = alc885_macmini3_6ch_modes,
10112 .num_channel_mode = ARRAY_SIZE(alc885_macmini3_6ch_modes),
10113 .input_mux = &macmini3_capture_source,
10114 .dig_out_nid = ALC882_DIGOUT_NID,
10115 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +010010116 .unsol_event = alc_automute_amp_unsol_event,
10117 .setup = alc885_macmini3_setup,
10118 .init_hook = alc_automute_amp,
Luke Yelaviche458b1f2010-02-12 16:28:29 +110010119 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020010120 [ALC885_MACPRO] = {
10121 .mixers = { alc882_macpro_mixer },
10122 .init_verbs = { alc882_macpro_init_verbs },
10123 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10124 .dac_nids = alc882_dac_nids,
10125 .dig_out_nid = ALC882_DIGOUT_NID,
10126 .dig_in_nid = ALC882_DIGIN_NID,
10127 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
10128 .channel_mode = alc882_ch_modes,
10129 .input_mux = &alc882_capture_source,
10130 .init_hook = alc885_macpro_init_hook,
10131 },
10132 [ALC885_IMAC24] = {
10133 .mixers = { alc885_imac24_mixer },
10134 .init_verbs = { alc885_imac24_init_verbs },
10135 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10136 .dac_nids = alc882_dac_nids,
10137 .dig_out_nid = ALC882_DIGOUT_NID,
10138 .dig_in_nid = ALC882_DIGIN_NID,
10139 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
10140 .channel_mode = alc882_ch_modes,
10141 .input_mux = &alc882_capture_source,
10142 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010143 .setup = alc885_imac24_setup,
Takashi Iwai4953550a2009-06-30 15:28:30 +020010144 .init_hook = alc885_imac24_init_hook,
10145 },
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010146 [ALC885_IMAC91] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -070010147 .mixers = {alc885_imac91_mixer},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010148 .init_verbs = { alc885_imac91_init_verbs,
10149 alc880_gpio1_init_verbs },
10150 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10151 .dac_nids = alc882_dac_nids,
Justin P. Mattockb7cccc52010-05-23 10:55:00 -070010152 .channel_mode = alc885_mba21_ch_modes,
10153 .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
10154 .input_mux = &alc889A_imac91_capture_source,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010155 .dig_out_nid = ALC882_DIGOUT_NID,
10156 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +010010157 .unsol_event = alc_automute_amp_unsol_event,
10158 .setup = alc885_imac91_setup,
10159 .init_hook = alc_automute_amp,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010160 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020010161 [ALC882_TARGA] = {
10162 .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010163 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
Takashi Iwai31909b82009-07-10 12:33:48 +020010164 alc880_gpio3_init_verbs, alc882_targa_verbs},
Takashi Iwai4953550a2009-06-30 15:28:30 +020010165 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10166 .dac_nids = alc882_dac_nids,
10167 .dig_out_nid = ALC882_DIGOUT_NID,
10168 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
10169 .adc_nids = alc882_adc_nids,
10170 .capsrc_nids = alc882_capsrc_nids,
10171 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
10172 .channel_mode = alc882_3ST_6ch_modes,
10173 .need_dac_fix = 1,
10174 .input_mux = &alc882_capture_source,
10175 .unsol_event = alc882_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010176 .setup = alc882_targa_setup,
10177 .init_hook = alc882_targa_automute,
Takashi Iwai4953550a2009-06-30 15:28:30 +020010178 },
10179 [ALC882_ASUS_A7J] = {
10180 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010181 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10182 alc882_asus_a7j_verbs},
Takashi Iwai4953550a2009-06-30 15:28:30 +020010183 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10184 .dac_nids = alc882_dac_nids,
10185 .dig_out_nid = ALC882_DIGOUT_NID,
10186 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
10187 .adc_nids = alc882_adc_nids,
10188 .capsrc_nids = alc882_capsrc_nids,
10189 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
10190 .channel_mode = alc882_3ST_6ch_modes,
10191 .need_dac_fix = 1,
10192 .input_mux = &alc882_capture_source,
10193 },
10194 [ALC882_ASUS_A7M] = {
10195 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010196 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10197 alc882_eapd_verbs, alc880_gpio1_init_verbs,
Takashi Iwai4953550a2009-06-30 15:28:30 +020010198 alc882_asus_a7m_verbs },
10199 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10200 .dac_nids = alc882_dac_nids,
10201 .dig_out_nid = ALC882_DIGOUT_NID,
10202 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
10203 .channel_mode = alc880_threestack_modes,
10204 .need_dac_fix = 1,
10205 .input_mux = &alc882_capture_source,
10206 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010207 [ALC883_3ST_2ch_DIG] = {
10208 .mixers = { alc883_3ST_2ch_mixer },
10209 .init_verbs = { alc883_init_verbs },
10210 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10211 .dac_nids = alc883_dac_nids,
10212 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010213 .dig_in_nid = ALC883_DIGIN_NID,
10214 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10215 .channel_mode = alc883_3ST_2ch_modes,
10216 .input_mux = &alc883_capture_source,
10217 },
10218 [ALC883_3ST_6ch_DIG] = {
10219 .mixers = { alc883_3ST_6ch_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,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010224 .dig_in_nid = ALC883_DIGIN_NID,
10225 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10226 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020010227 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010228 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010229 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010230 [ALC883_3ST_6ch] = {
10231 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10232 .init_verbs = { alc883_init_verbs },
10233 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10234 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010235 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10236 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020010237 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010238 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010239 },
Jiang zhe17bba1b2008-06-04 12:11:07 +020010240 [ALC883_3ST_6ch_INTEL] = {
10241 .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
10242 .init_verbs = { alc883_init_verbs },
10243 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10244 .dac_nids = alc883_dac_nids,
10245 .dig_out_nid = ALC883_DIGOUT_NID,
10246 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangf3cd3f52009-04-02 19:44:18 +080010247 .slave_dig_outs = alc883_slave_dig_outs,
Jiang zhe17bba1b2008-06-04 12:11:07 +020010248 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
10249 .channel_mode = alc883_3ST_6ch_intel_modes,
10250 .need_dac_fix = 1,
10251 .input_mux = &alc883_3stack_6ch_intel,
10252 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010253 [ALC889A_INTEL] = {
10254 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020010255 .init_verbs = { alc885_init_verbs, alc885_init_input_verbs,
10256 alc_hp15_unsol_verbs },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010257 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10258 .dac_nids = alc883_dac_nids,
10259 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10260 .adc_nids = alc889_adc_nids,
10261 .dig_out_nid = ALC883_DIGOUT_NID,
10262 .dig_in_nid = ALC883_DIGIN_NID,
10263 .slave_dig_outs = alc883_slave_dig_outs,
10264 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
10265 .channel_mode = alc889_8ch_intel_modes,
10266 .capsrc_nids = alc889_capsrc_nids,
10267 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010268 .setup = alc889_automute_setup,
10269 .init_hook = alc_automute_amp,
Wu Fengguang6732bd02009-07-30 09:19:14 +020010270 .unsol_event = alc_automute_amp_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010271 .need_dac_fix = 1,
10272 },
10273 [ALC889_INTEL] = {
10274 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
10275 .init_verbs = { alc885_init_verbs, alc889_init_input_verbs,
Wu Fengguang6732bd02009-07-30 09:19:14 +020010276 alc889_eapd_verbs, alc_hp15_unsol_verbs},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010277 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10278 .dac_nids = alc883_dac_nids,
10279 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10280 .adc_nids = alc889_adc_nids,
10281 .dig_out_nid = ALC883_DIGOUT_NID,
10282 .dig_in_nid = ALC883_DIGIN_NID,
10283 .slave_dig_outs = alc883_slave_dig_outs,
10284 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
10285 .channel_mode = alc889_8ch_intel_modes,
10286 .capsrc_nids = alc889_capsrc_nids,
10287 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010288 .setup = alc889_automute_setup,
Wu Fengguang6732bd02009-07-30 09:19:14 +020010289 .init_hook = alc889_intel_init_hook,
10290 .unsol_event = alc_automute_amp_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010291 .need_dac_fix = 1,
10292 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010293 [ALC883_6ST_DIG] = {
10294 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
10295 .init_verbs = { alc883_init_verbs },
10296 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10297 .dac_nids = alc883_dac_nids,
10298 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010299 .dig_in_nid = ALC883_DIGIN_NID,
10300 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10301 .channel_mode = alc883_sixstack_modes,
10302 .input_mux = &alc883_capture_source,
10303 },
Kailang Yangccc656c2006-10-17 12:32:26 +020010304 [ALC883_TARGA_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010305 .mixers = { alc883_targa_mixer, alc883_chmode_mixer },
David Heidelberger005b1072009-07-09 18:45:46 +020010306 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
10307 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020010308 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10309 .dac_nids = alc883_dac_nids,
10310 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +020010311 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10312 .channel_mode = alc883_3ST_6ch_modes,
10313 .need_dac_fix = 1,
10314 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010315 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010316 .setup = alc882_targa_setup,
10317 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010318 },
10319 [ALC883_TARGA_2ch_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010320 .mixers = { alc883_targa_2ch_mixer},
David Heidelberger005b1072009-07-09 18:45:46 +020010321 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
10322 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020010323 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10324 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010325 .adc_nids = alc883_adc_nids_alt,
10326 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010327 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangccc656c2006-10-17 12:32:26 +020010328 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +020010329 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10330 .channel_mode = alc883_3ST_2ch_modes,
10331 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010332 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010333 .setup = alc882_targa_setup,
10334 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010335 },
David Heidelberger64a8be72009-06-08 16:15:18 +020010336 [ALC883_TARGA_8ch_DIG] = {
Takashi Iwaib99dba32009-09-17 18:23:00 +020010337 .mixers = { alc883_targa_mixer, alc883_targa_8ch_mixer,
10338 alc883_chmode_mixer },
David Heidelberger64a8be72009-06-08 16:15:18 +020010339 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010340 alc883_targa_verbs },
David Heidelberger64a8be72009-06-08 16:15:18 +020010341 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10342 .dac_nids = alc883_dac_nids,
10343 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10344 .adc_nids = alc883_adc_nids_rev,
10345 .capsrc_nids = alc883_capsrc_nids_rev,
10346 .dig_out_nid = ALC883_DIGOUT_NID,
10347 .dig_in_nid = ALC883_DIGIN_NID,
10348 .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes),
10349 .channel_mode = alc883_4ST_8ch_modes,
10350 .need_dac_fix = 1,
10351 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010352 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010353 .setup = alc882_targa_setup,
10354 .init_hook = alc882_targa_automute,
David Heidelberger64a8be72009-06-08 16:15:18 +020010355 },
Vladimir Avdoninbab282b92006-08-22 13:31:58 +020010356 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010357 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b92006-08-22 13:31:58 +020010358 /* On TravelMate laptops, GPIO 0 enables the internal speaker
10359 * and the headphone jack. Turn this on and rely on the
10360 * standard mute methods whenever the user wants to turn
10361 * these outputs off.
10362 */
10363 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
10364 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10365 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b92006-08-22 13:31:58 +020010366 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10367 .channel_mode = alc883_3ST_2ch_modes,
10368 .input_mux = &alc883_capture_source,
10369 },
Tobin Davis2880a862007-08-07 11:50:26 +020010370 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010371 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +020010372 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +020010373 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10374 .dac_nids = alc883_dac_nids,
10375 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +020010376 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10377 .channel_mode = alc883_3ST_2ch_modes,
10378 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010379 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010380 .setup = alc883_acer_aspire_setup,
10381 .init_hook = alc_automute_amp,
Kailang Yangd1a991a2007-08-15 16:21:59 +020010382 },
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010383 [ALC888_ACER_ASPIRE_4930G] = {
Łukasz Wojniłowicz460c92f2011-02-07 13:13:27 +010010384 .mixers = { alc888_acer_aspire_4930g_mixer,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010385 alc883_chmode_mixer },
10386 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10387 alc888_acer_aspire_4930g_verbs },
10388 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10389 .dac_nids = alc883_dac_nids,
10390 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10391 .adc_nids = alc883_adc_nids_rev,
10392 .capsrc_nids = alc883_capsrc_nids_rev,
10393 .dig_out_nid = ALC883_DIGOUT_NID,
10394 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10395 .channel_mode = alc883_3ST_6ch_modes,
10396 .need_dac_fix = 1,
Łukasz Wojniłowicz973b8cb2010-01-24 14:12:37 +010010397 .const_channel_count = 6,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010398 .num_mux_defs =
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010399 ARRAY_SIZE(alc888_2_capture_sources),
10400 .input_mux = alc888_2_capture_sources,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010401 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010402 .setup = alc888_acer_aspire_4930g_setup,
10403 .init_hook = alc_automute_amp,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010404 },
Tony Vroond2fd4b02009-06-21 00:40:10 +010010405 [ALC888_ACER_ASPIRE_6530G] = {
10406 .mixers = { alc888_acer_aspire_6530_mixer },
10407 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10408 alc888_acer_aspire_6530g_verbs },
10409 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10410 .dac_nids = alc883_dac_nids,
10411 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10412 .adc_nids = alc883_adc_nids_rev,
10413 .capsrc_nids = alc883_capsrc_nids_rev,
10414 .dig_out_nid = ALC883_DIGOUT_NID,
10415 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10416 .channel_mode = alc883_3ST_2ch_modes,
10417 .num_mux_defs =
10418 ARRAY_SIZE(alc888_2_capture_sources),
10419 .input_mux = alc888_acer_aspire_6530_sources,
10420 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010421 .setup = alc888_acer_aspire_6530g_setup,
10422 .init_hook = alc_automute_amp,
Tony Vroond2fd4b02009-06-21 00:40:10 +010010423 },
Hector Martin3b315d72009-06-02 10:54:19 +020010424 [ALC888_ACER_ASPIRE_8930G] = {
Hector Martin556eea92009-12-20 22:51:23 +010010425 .mixers = { alc889_acer_aspire_8930g_mixer,
Hector Martin3b315d72009-06-02 10:54:19 +020010426 alc883_chmode_mixer },
10427 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
Hector Martin0f86a222009-12-20 22:51:18 +010010428 alc889_acer_aspire_8930g_verbs,
10429 alc889_eapd_verbs},
Hector Martin3b315d72009-06-02 10:54:19 +020010430 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10431 .dac_nids = alc883_dac_nids,
Hector Martin018df412009-06-04 00:13:40 +020010432 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10433 .adc_nids = alc889_adc_nids,
10434 .capsrc_nids = alc889_capsrc_nids,
Hector Martin3b315d72009-06-02 10:54:19 +020010435 .dig_out_nid = ALC883_DIGOUT_NID,
10436 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10437 .channel_mode = alc883_3ST_6ch_modes,
10438 .need_dac_fix = 1,
10439 .const_channel_count = 6,
10440 .num_mux_defs =
Hector Martin018df412009-06-04 00:13:40 +020010441 ARRAY_SIZE(alc889_capture_sources),
10442 .input_mux = alc889_capture_sources,
Hector Martin3b315d72009-06-02 10:54:19 +020010443 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010444 .setup = alc889_acer_aspire_8930g_setup,
10445 .init_hook = alc_automute_amp,
Hector Martinf5de24b2009-12-20 22:51:31 +010010446#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050010447 .power_hook = alc_power_eapd,
Hector Martinf5de24b2009-12-20 22:51:31 +010010448#endif
Hector Martin3b315d72009-06-02 10:54:19 +020010449 },
Denis Kuplyakovfc86f952009-08-25 18:15:59 +020010450 [ALC888_ACER_ASPIRE_7730G] = {
10451 .mixers = { alc883_3ST_6ch_mixer,
10452 alc883_chmode_mixer },
10453 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10454 alc888_acer_aspire_7730G_verbs },
10455 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10456 .dac_nids = alc883_dac_nids,
10457 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10458 .adc_nids = alc883_adc_nids_rev,
10459 .capsrc_nids = alc883_capsrc_nids_rev,
10460 .dig_out_nid = ALC883_DIGOUT_NID,
10461 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10462 .channel_mode = alc883_3ST_6ch_modes,
10463 .need_dac_fix = 1,
10464 .const_channel_count = 6,
10465 .input_mux = &alc883_capture_source,
10466 .unsol_event = alc_automute_amp_unsol_event,
Denis Kuplyakovd9477202010-11-24 06:01:09 +010010467 .setup = alc888_acer_aspire_7730g_setup,
Denis Kuplyakovfc86f952009-08-25 18:15:59 +020010468 .init_hook = alc_automute_amp,
10469 },
Tobin Davisc07584c2006-10-13 12:32:16 +020010470 [ALC883_MEDION] = {
10471 .mixers = { alc883_fivestack_mixer,
10472 alc883_chmode_mixer },
10473 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010474 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +020010475 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10476 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010477 .adc_nids = alc883_adc_nids_alt,
10478 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010479 .capsrc_nids = alc883_capsrc_nids,
Tobin Davisc07584c2006-10-13 12:32:16 +020010480 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10481 .channel_mode = alc883_sixstack_modes,
10482 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010483 },
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +020010484 [ALC883_MEDION_WIM2160] = {
10485 .mixers = { alc883_medion_wim2160_mixer },
10486 .init_verbs = { alc883_init_verbs, alc883_medion_wim2160_verbs },
10487 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10488 .dac_nids = alc883_dac_nids,
10489 .dig_out_nid = ALC883_DIGOUT_NID,
10490 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
10491 .adc_nids = alc883_adc_nids,
10492 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10493 .channel_mode = alc883_3ST_2ch_modes,
10494 .input_mux = &alc883_capture_source,
10495 .unsol_event = alc_automute_amp_unsol_event,
10496 .setup = alc883_medion_wim2160_setup,
10497 .init_hook = alc_automute_amp,
10498 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010499 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010500 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010501 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
10502 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10503 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010504 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10505 .channel_mode = alc883_3ST_2ch_modes,
10506 .input_mux = &alc883_capture_source,
10507 },
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -043010508 [ALC883_CLEVO_M540R] = {
10509 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10510 .init_verbs = { alc883_init_verbs, alc883_clevo_m540r_verbs },
10511 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10512 .dac_nids = alc883_dac_nids,
10513 .dig_out_nid = ALC883_DIGOUT_NID,
10514 .dig_in_nid = ALC883_DIGIN_NID,
10515 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_clevo_modes),
10516 .channel_mode = alc883_3ST_6ch_clevo_modes,
10517 .need_dac_fix = 1,
10518 .input_mux = &alc883_capture_source,
10519 /* This machine has the hardware HP auto-muting, thus
10520 * we need no software mute via unsol event
10521 */
10522 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010523 [ALC883_CLEVO_M720] = {
10524 .mixers = { alc883_clevo_m720_mixer },
10525 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +010010526 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10527 .dac_nids = alc883_dac_nids,
10528 .dig_out_nid = ALC883_DIGOUT_NID,
10529 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10530 .channel_mode = alc883_3ST_2ch_modes,
10531 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010532 .unsol_event = alc883_clevo_m720_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010533 .setup = alc883_clevo_m720_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010534 .init_hook = alc883_clevo_m720_init_hook,
Jiang zhe368c7a92008-03-04 11:20:33 +010010535 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010536 [ALC883_LENOVO_101E_2ch] = {
10537 .mixers = { alc883_lenovo_101e_2ch_mixer},
10538 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
10539 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10540 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010541 .adc_nids = alc883_adc_nids_alt,
10542 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010543 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010544 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10545 .channel_mode = alc883_3ST_2ch_modes,
10546 .input_mux = &alc883_lenovo_101e_capture_source,
10547 .unsol_event = alc883_lenovo_101e_unsol_event,
10548 .init_hook = alc883_lenovo_101e_all_automute,
10549 },
Kailang Yang272a5272007-05-14 11:00:38 +020010550 [ALC883_LENOVO_NB0763] = {
10551 .mixers = { alc883_lenovo_nb0763_mixer },
10552 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
10553 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10554 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020010555 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10556 .channel_mode = alc883_3ST_2ch_modes,
10557 .need_dac_fix = 1,
10558 .input_mux = &alc883_lenovo_nb0763_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010559 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwaidc4271702010-11-29 07:42:59 +010010560 .setup = alc883_lenovo_nb0763_setup,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010561 .init_hook = alc_automute_amp,
Kailang Yang272a5272007-05-14 11:00:38 +020010562 },
10563 [ALC888_LENOVO_MS7195_DIG] = {
10564 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10565 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
10566 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10567 .dac_nids = alc883_dac_nids,
10568 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +020010569 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10570 .channel_mode = alc883_3ST_6ch_modes,
10571 .need_dac_fix = 1,
10572 .input_mux = &alc883_capture_source,
10573 .unsol_event = alc883_lenovo_ms7195_unsol_event,
10574 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +020010575 },
10576 [ALC883_HAIER_W66] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010577 .mixers = { alc883_targa_2ch_mixer},
Kailang Yang189609a2007-08-20 11:31:23 +020010578 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
10579 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10580 .dac_nids = alc883_dac_nids,
10581 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +020010582 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10583 .channel_mode = alc883_3ST_2ch_modes,
10584 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010585 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010586 .setup = alc883_haier_w66_setup,
10587 .init_hook = alc_automute_amp,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +010010588 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010589 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +010010590 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010591 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010592 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10593 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010594 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
10595 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010596 .need_dac_fix = 1,
10597 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010598 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010599 .setup = alc888_3st_hp_setup,
10600 .init_hook = alc_automute_amp,
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010601 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010602 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +010010603 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010604 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
10605 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10606 .dac_nids = alc883_dac_nids,
10607 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010608 .dig_in_nid = ALC883_DIGIN_NID,
10609 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10610 .channel_mode = alc883_sixstack_modes,
10611 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010612 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010613 .setup = alc888_6st_dell_setup,
10614 .init_hook = alc_automute_amp,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010615 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010616 [ALC883_MITAC] = {
10617 .mixers = { alc883_mitac_mixer },
10618 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
10619 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10620 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010621 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10622 .channel_mode = alc883_3ST_2ch_modes,
10623 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010624 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010625 .setup = alc883_mitac_setup,
10626 .init_hook = alc_automute_amp,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010627 },
Jiang zhefb97dc62008-03-06 11:07:11 +010010628 [ALC883_FUJITSU_PI2515] = {
10629 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
10630 .init_verbs = { alc883_init_verbs,
10631 alc883_2ch_fujitsu_pi2515_verbs},
10632 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10633 .dac_nids = alc883_dac_nids,
10634 .dig_out_nid = ALC883_DIGOUT_NID,
10635 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10636 .channel_mode = alc883_3ST_2ch_modes,
10637 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010638 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010639 .setup = alc883_2ch_fujitsu_pi2515_setup,
10640 .init_hook = alc_automute_amp,
Jiang zhefb97dc62008-03-06 11:07:11 +010010641 },
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010642 [ALC888_FUJITSU_XA3530] = {
10643 .mixers = { alc888_base_mixer, alc883_chmode_mixer },
10644 .init_verbs = { alc883_init_verbs,
10645 alc888_fujitsu_xa3530_verbs },
10646 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10647 .dac_nids = alc883_dac_nids,
10648 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10649 .adc_nids = alc883_adc_nids_rev,
10650 .capsrc_nids = alc883_capsrc_nids_rev,
10651 .dig_out_nid = ALC883_DIGOUT_NID,
10652 .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes),
10653 .channel_mode = alc888_4ST_8ch_intel_modes,
10654 .num_mux_defs =
10655 ARRAY_SIZE(alc888_2_capture_sources),
10656 .input_mux = alc888_2_capture_sources,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010657 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010658 .setup = alc888_fujitsu_xa3530_setup,
10659 .init_hook = alc_automute_amp,
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010660 },
Kailang Yange2757d52008-08-26 13:17:46 +020010661 [ALC888_LENOVO_SKY] = {
10662 .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
10663 .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
10664 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10665 .dac_nids = alc883_dac_nids,
10666 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yange2757d52008-08-26 13:17:46 +020010667 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10668 .channel_mode = alc883_sixstack_modes,
10669 .need_dac_fix = 1,
10670 .input_mux = &alc883_lenovo_sky_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010671 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010672 .setup = alc888_lenovo_sky_setup,
10673 .init_hook = alc_automute_amp,
Kailang Yange2757d52008-08-26 13:17:46 +020010674 },
10675 [ALC888_ASUS_M90V] = {
10676 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10677 .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
10678 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10679 .dac_nids = alc883_dac_nids,
10680 .dig_out_nid = ALC883_DIGOUT_NID,
10681 .dig_in_nid = ALC883_DIGIN_NID,
10682 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10683 .channel_mode = alc883_3ST_6ch_modes,
10684 .need_dac_fix = 1,
10685 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010686 .unsol_event = alc_sku_unsol_event,
10687 .setup = alc883_mode2_setup,
10688 .init_hook = alc_inithook,
Kailang Yange2757d52008-08-26 13:17:46 +020010689 },
10690 [ALC888_ASUS_EEE1601] = {
10691 .mixers = { alc883_asus_eee1601_mixer },
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010692 .cap_mixer = alc883_asus_eee1601_cap_mixer,
Kailang Yange2757d52008-08-26 13:17:46 +020010693 .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
10694 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10695 .dac_nids = alc883_dac_nids,
10696 .dig_out_nid = ALC883_DIGOUT_NID,
10697 .dig_in_nid = ALC883_DIGIN_NID,
10698 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10699 .channel_mode = alc883_3ST_2ch_modes,
10700 .need_dac_fix = 1,
10701 .input_mux = &alc883_asus_eee1601_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010702 .unsol_event = alc_sku_unsol_event,
Kailang Yange2757d52008-08-26 13:17:46 +020010703 .init_hook = alc883_eee1601_inithook,
10704 },
Wu Fengguang3ab90932008-11-17 09:51:09 +010010705 [ALC1200_ASUS_P5Q] = {
10706 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
10707 .init_verbs = { alc883_init_verbs },
10708 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10709 .dac_nids = alc883_dac_nids,
10710 .dig_out_nid = ALC1200_DIGOUT_NID,
10711 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangb25c9da2009-02-06 15:02:27 +080010712 .slave_dig_outs = alc1200_slave_dig_outs,
Wu Fengguang3ab90932008-11-17 09:51:09 +010010713 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10714 .channel_mode = alc883_sixstack_modes,
10715 .input_mux = &alc883_capture_source,
10716 },
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010717 [ALC889A_MB31] = {
10718 .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer},
10719 .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs,
10720 alc880_gpio1_init_verbs },
10721 .adc_nids = alc883_adc_nids,
10722 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010723 .capsrc_nids = alc883_capsrc_nids,
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010724 .dac_nids = alc883_dac_nids,
10725 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10726 .channel_mode = alc889A_mb31_6ch_modes,
10727 .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes),
10728 .input_mux = &alc889A_mb31_capture_source,
10729 .dig_out_nid = ALC883_DIGOUT_NID,
10730 .unsol_event = alc889A_mb31_unsol_event,
10731 .init_hook = alc889A_mb31_automute,
10732 },
Guido Günther3e1647c52009-06-05 00:47:26 +020010733 [ALC883_SONY_VAIO_TT] = {
10734 .mixers = { alc883_vaiott_mixer },
10735 .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs },
10736 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10737 .dac_nids = alc883_dac_nids,
10738 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10739 .channel_mode = alc883_3ST_2ch_modes,
10740 .input_mux = &alc883_capture_source,
10741 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010742 .setup = alc883_vaiott_setup,
10743 .init_hook = alc_automute_amp,
Guido Günther3e1647c52009-06-05 00:47:26 +020010744 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010745};
10746
10747
10748/*
Takashi Iwai4953550a2009-06-30 15:28:30 +020010749 * Pin config fixes
10750 */
10751enum {
Takashi Iwai954a29c2010-07-30 10:55:44 +020010752 PINFIX_ABIT_AW9D_MAX,
10753 PINFIX_PB_M5210,
David Henningssonc3d226a2010-10-14 15:42:08 +020010754 PINFIX_ACER_ASPIRE_7736,
Takashi Iwai4953550a2009-06-30 15:28:30 +020010755};
10756
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010757static const struct alc_fixup alc882_fixups[] = {
10758 [PINFIX_ABIT_AW9D_MAX] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010010759 .type = ALC_FIXUP_PINS,
10760 .v.pins = (const struct alc_pincfg[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020010761 { 0x15, 0x01080104 }, /* side */
10762 { 0x16, 0x01011012 }, /* rear */
10763 { 0x17, 0x01016011 }, /* clfe */
10764 { }
10765 }
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010766 },
Takashi Iwai954a29c2010-07-30 10:55:44 +020010767 [PINFIX_PB_M5210] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010010768 .type = ALC_FIXUP_VERBS,
10769 .v.verbs = (const struct hda_verb[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020010770 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
10771 {}
10772 }
Takashi Iwai954a29c2010-07-30 10:55:44 +020010773 },
David Henningssonc3d226a2010-10-14 15:42:08 +020010774 [PINFIX_ACER_ASPIRE_7736] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010010775 .type = ALC_FIXUP_SKU,
10776 .v.sku = ALC_FIXUP_SKU_IGNORE,
David Henningssonc3d226a2010-10-14 15:42:08 +020010777 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020010778};
10779
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010780static struct snd_pci_quirk alc882_fixup_tbl[] = {
Takashi Iwai954a29c2010-07-30 10:55:44 +020010781 SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
Takashi Iwai4953550a2009-06-30 15:28:30 +020010782 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
David Henningssonc3d226a2010-10-14 15:42:08 +020010783 SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736),
Takashi Iwai4953550a2009-06-30 15:28:30 +020010784 {}
10785};
10786
10787/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010788 * BIOS auto configuration
10789 */
Takashi Iwai05f5f472009-08-25 13:10:18 +020010790static int alc882_auto_create_input_ctls(struct hda_codec *codec,
10791 const struct auto_pin_cfg *cfg)
10792{
10793 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x23, 0x22);
10794}
10795
Takashi Iwai4953550a2009-06-30 15:28:30 +020010796static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010797 hda_nid_t nid, int pin_type,
Takashi Iwai489008c2010-04-07 09:06:00 +020010798 hda_nid_t dac)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010799{
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010800 int idx;
10801
Takashi Iwai489008c2010-04-07 09:06:00 +020010802 /* set as output */
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010803 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010804
Takashi Iwai489008c2010-04-07 09:06:00 +020010805 if (dac == 0x25)
10806 idx = 4;
10807 else if (dac >= 0x02 && dac <= 0x05)
10808 idx = dac - 2;
10809 else
10810 return;
10811 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010812}
10813
Takashi Iwai4953550a2009-06-30 15:28:30 +020010814static void alc882_auto_init_multi_out(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010815{
10816 struct alc_spec *spec = codec->spec;
10817 int i;
10818
10819 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010820 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020010821 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010822 if (nid)
Takashi Iwai4953550a2009-06-30 15:28:30 +020010823 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai489008c2010-04-07 09:06:00 +020010824 spec->multiout.dac_nids[i]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010825 }
10826}
10827
Takashi Iwai4953550a2009-06-30 15:28:30 +020010828static void alc882_auto_init_hp_out(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010829{
10830 struct alc_spec *spec = codec->spec;
Takashi Iwai489008c2010-04-07 09:06:00 +020010831 hda_nid_t pin, dac;
Takashi Iwai5855fb82010-09-16 18:24:02 +020010832 int i;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010833
Takashi Iwai5855fb82010-09-16 18:24:02 +020010834 for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
10835 pin = spec->autocfg.hp_pins[i];
10836 if (!pin)
10837 break;
Takashi Iwai489008c2010-04-07 09:06:00 +020010838 dac = spec->multiout.hp_nid;
10839 if (!dac)
10840 dac = spec->multiout.dac_nids[0]; /* to front */
10841 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
10842 }
Takashi Iwai5855fb82010-09-16 18:24:02 +020010843 for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
10844 pin = spec->autocfg.speaker_pins[i];
10845 if (!pin)
10846 break;
Takashi Iwai489008c2010-04-07 09:06:00 +020010847 dac = spec->multiout.extra_out_nid[0];
10848 if (!dac)
10849 dac = spec->multiout.dac_nids[0]; /* to front */
10850 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
10851 }
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010852}
10853
Takashi Iwai4953550a2009-06-30 15:28:30 +020010854static void alc882_auto_init_analog_input(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010855{
10856 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010857 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010858 int i;
10859
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010860 for (i = 0; i < cfg->num_inputs; i++) {
10861 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai30ea0982010-09-16 18:47:56 +020010862 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwai4953550a2009-06-30 15:28:30 +020010863 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
10864 snd_hda_codec_write(codec, nid, 0,
10865 AC_VERB_SET_AMP_GAIN_MUTE,
10866 AMP_OUT_MUTE);
10867 }
10868}
10869
10870static void alc882_auto_init_input_src(struct hda_codec *codec)
10871{
10872 struct alc_spec *spec = codec->spec;
10873 int c;
10874
10875 for (c = 0; c < spec->num_adc_nids; c++) {
10876 hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
10877 hda_nid_t nid = spec->capsrc_nids[c];
10878 unsigned int mux_idx;
10879 const struct hda_input_mux *imux;
10880 int conns, mute, idx, item;
10881
10882 conns = snd_hda_get_connections(codec, nid, conn_list,
10883 ARRAY_SIZE(conn_list));
10884 if (conns < 0)
10885 continue;
10886 mux_idx = c >= spec->num_mux_defs ? 0 : c;
10887 imux = &spec->input_mux[mux_idx];
Takashi Iwai53111142010-03-08 12:13:07 +010010888 if (!imux->num_items && mux_idx > 0)
10889 imux = &spec->input_mux[0];
Takashi Iwai4953550a2009-06-30 15:28:30 +020010890 for (idx = 0; idx < conns; idx++) {
10891 /* if the current connection is the selected one,
10892 * unmute it as default - otherwise mute it
10893 */
10894 mute = AMP_IN_MUTE(idx);
10895 for (item = 0; item < imux->num_items; item++) {
10896 if (imux->items[item].index == idx) {
10897 if (spec->cur_mux[c] == item)
10898 mute = AMP_IN_UNMUTE(idx);
10899 break;
10900 }
10901 }
10902 /* check if we have a selector or mixer
10903 * we could check for the widget type instead, but
10904 * just check for Amp-In presence (in case of mixer
10905 * without amp-in there is something wrong, this
10906 * function shouldn't be used or capsrc nid is wrong)
10907 */
10908 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010909 snd_hda_codec_write(codec, nid, 0,
10910 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwai4953550a2009-06-30 15:28:30 +020010911 mute);
10912 else if (mute != AMP_IN_MUTE(idx))
10913 snd_hda_codec_write(codec, nid, 0,
10914 AC_VERB_SET_CONNECT_SEL,
10915 idx);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010916 }
10917 }
10918}
10919
Takashi Iwai4953550a2009-06-30 15:28:30 +020010920/* add mic boosts if needed */
10921static int alc_auto_add_mic_boost(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010922{
10923 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010924 struct auto_pin_cfg *cfg = &spec->autocfg;
David Henningsson5322bf22011-01-05 11:03:56 +010010925 int i, err;
Takashi Iwai53e8c322010-12-17 15:23:41 +010010926 int type_idx = 0;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010927 hda_nid_t nid;
David Henningsson5322bf22011-01-05 11:03:56 +010010928 const char *prev_label = NULL;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010929
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010930 for (i = 0; i < cfg->num_inputs; i++) {
Takashi Iwai86e29592010-09-09 14:50:17 +020010931 if (cfg->inputs[i].type > AUTO_PIN_MIC)
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010932 break;
10933 nid = cfg->inputs[i].pin;
10934 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
David Henningsson5322bf22011-01-05 11:03:56 +010010935 const char *label;
10936 char boost_label[32];
10937
10938 label = hda_get_autocfg_input_label(codec, cfg, i);
10939 if (prev_label && !strcmp(label, prev_label))
Takashi Iwai53e8c322010-12-17 15:23:41 +010010940 type_idx++;
10941 else
10942 type_idx = 0;
David Henningsson5322bf22011-01-05 11:03:56 +010010943 prev_label = label;
10944
10945 snprintf(boost_label, sizeof(boost_label),
10946 "%s Boost Volume", label);
10947 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10948 boost_label, type_idx,
Takashi Iwai4953550a2009-06-30 15:28:30 +020010949 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010950 if (err < 0)
10951 return err;
10952 }
Takashi Iwai4953550a2009-06-30 15:28:30 +020010953 }
10954 return 0;
10955}
10956
10957/* almost identical with ALC880 parser... */
10958static int alc882_parse_auto_config(struct hda_codec *codec)
10959{
10960 struct alc_spec *spec = codec->spec;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010961 static hda_nid_t alc882_ignore[] = { 0x1d, 0 };
Takashi Iwai757899a2010-07-30 10:48:14 +020010962 int err;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010963
Takashi Iwai05f5f472009-08-25 13:10:18 +020010964 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10965 alc882_ignore);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010966 if (err < 0)
10967 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010968 if (!spec->autocfg.line_outs)
10969 return 0; /* can't find valid BIOS pin config */
10970
10971 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
10972 if (err < 0)
10973 return err;
Takashi Iwai569ed342011-01-19 10:14:46 +010010974 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
Takashi Iwai05f5f472009-08-25 13:10:18 +020010975 if (err < 0)
10976 return err;
Takashi Iwai489008c2010-04-07 09:06:00 +020010977 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
10978 "Headphone");
10979 if (err < 0)
10980 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010981 err = alc880_auto_create_extra_out(spec,
10982 spec->autocfg.speaker_pins[0],
10983 "Speaker");
10984 if (err < 0)
10985 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010986 err = alc882_auto_create_input_ctls(codec, &spec->autocfg);
10987 if (err < 0)
10988 return err;
10989
10990 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10991
Takashi Iwai757899a2010-07-30 10:48:14 +020010992 alc_auto_parse_digital(codec);
Takashi Iwai05f5f472009-08-25 13:10:18 +020010993
10994 if (spec->kctls.list)
10995 add_mixer(spec, spec->kctls.list);
10996
10997 add_verb(spec, alc883_auto_init_verbs);
10998 /* if ADC 0x07 is available, initialize it, too */
10999 if (get_wcaps_type(get_wcaps(codec, 0x07)) == AC_WID_AUD_IN)
11000 add_verb(spec, alc882_adc1_init_verbs);
11001
11002 spec->num_mux_defs = 1;
11003 spec->input_mux = &spec->private_imux[0];
11004
Kailang Yang6227cdc2010-02-25 08:36:52 +010011005 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai776e1842007-08-29 15:07:11 +020011006
11007 err = alc_auto_add_mic_boost(codec);
11008 if (err < 0)
11009 return err;
11010
Takashi Iwai776e1842007-08-29 15:07:11 +020011011 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011012}
11013
11014/* additional initialization for auto-configuration model */
Takashi Iwai4953550a2009-06-30 15:28:30 +020011015static void alc882_auto_init(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011016{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011017 struct alc_spec *spec = codec->spec;
Takashi Iwai4953550a2009-06-30 15:28:30 +020011018 alc882_auto_init_multi_out(codec);
11019 alc882_auto_init_hp_out(codec);
11020 alc882_auto_init_analog_input(codec);
11021 alc882_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020011022 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011023 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020011024 alc_inithook(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011025}
11026
Takashi Iwai4953550a2009-06-30 15:28:30 +020011027static int patch_alc882(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011028{
11029 struct alc_spec *spec;
11030 int err, board_config;
11031
11032 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
11033 if (spec == NULL)
11034 return -ENOMEM;
11035
11036 codec->spec = spec;
11037
Takashi Iwai4953550a2009-06-30 15:28:30 +020011038 switch (codec->vendor_id) {
11039 case 0x10ec0882:
11040 case 0x10ec0885:
11041 break;
11042 default:
11043 /* ALC883 and variants */
11044 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
11045 break;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011046 }
11047
Takashi Iwai4953550a2009-06-30 15:28:30 +020011048 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
11049 alc882_models,
11050 alc882_cfg_tbl);
11051
11052 if (board_config < 0 || board_config >= ALC882_MODEL_LAST)
11053 board_config = snd_hda_check_board_codec_sid_config(codec,
11054 ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
11055
11056 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020011057 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai4953550a2009-06-30 15:28:30 +020011058 codec->chip_name);
11059 board_config = ALC882_AUTO;
11060 }
11061
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010011062 if (board_config == ALC882_AUTO) {
11063 alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups);
11064 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
11065 }
Takashi Iwai4953550a2009-06-30 15:28:30 +020011066
David Henningsson90622912010-10-14 14:50:18 +020011067 alc_auto_parse_customize_define(codec);
11068
Takashi Iwai4953550a2009-06-30 15:28:30 +020011069 if (board_config == ALC882_AUTO) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011070 /* automatic parse from the BIOS config */
Takashi Iwai4953550a2009-06-30 15:28:30 +020011071 err = alc882_parse_auto_config(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011072 if (err < 0) {
11073 alc_free(codec);
11074 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011075 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011076 printk(KERN_INFO
11077 "hda_codec: Cannot set up configuration "
11078 "from BIOS. Using base mode...\n");
Takashi Iwai4953550a2009-06-30 15:28:30 +020011079 board_config = ALC882_3ST_DIG;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011080 }
11081 }
11082
Takashi Iwaidc1eae22010-07-29 15:30:02 +020011083 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020011084 err = snd_hda_attach_beep_device(codec, 0x1);
11085 if (err < 0) {
11086 alc_free(codec);
11087 return err;
11088 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090011089 }
11090
Takashi Iwai4953550a2009-06-30 15:28:30 +020011091 if (board_config != ALC882_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020011092 setup_preset(codec, &alc882_presets[board_config]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011093
Takashi Iwai4953550a2009-06-30 15:28:30 +020011094 spec->stream_analog_playback = &alc882_pcm_analog_playback;
11095 spec->stream_analog_capture = &alc882_pcm_analog_capture;
11096 /* FIXME: setup DAC5 */
11097 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
11098 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
11099
11100 spec->stream_digital_playback = &alc882_pcm_digital_playback;
11101 spec->stream_digital_capture = &alc882_pcm_digital_capture;
11102
Takashi Iwai4953550a2009-06-30 15:28:30 +020011103 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010011104 int i, j;
Takashi Iwai4953550a2009-06-30 15:28:30 +020011105 spec->num_adc_nids = 0;
11106 for (i = 0; i < ARRAY_SIZE(alc882_adc_nids); i++) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010011107 const struct hda_input_mux *imux = spec->input_mux;
Takashi Iwai4953550a2009-06-30 15:28:30 +020011108 hda_nid_t cap;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010011109 hda_nid_t items[16];
Takashi Iwai4953550a2009-06-30 15:28:30 +020011110 hda_nid_t nid = alc882_adc_nids[i];
11111 unsigned int wcap = get_wcaps(codec, nid);
11112 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020011113 wcap = get_wcaps_type(wcap);
Takashi Iwai4953550a2009-06-30 15:28:30 +020011114 if (wcap != AC_WID_AUD_IN)
11115 continue;
11116 spec->private_adc_nids[spec->num_adc_nids] = nid;
11117 err = snd_hda_get_connections(codec, nid, &cap, 1);
11118 if (err < 0)
11119 continue;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010011120 err = snd_hda_get_connections(codec, cap, items,
11121 ARRAY_SIZE(items));
11122 if (err < 0)
11123 continue;
11124 for (j = 0; j < imux->num_items; j++)
11125 if (imux->items[j].index >= err)
11126 break;
11127 if (j < imux->num_items)
11128 continue;
Takashi Iwai4953550a2009-06-30 15:28:30 +020011129 spec->private_capsrc_nids[spec->num_adc_nids] = cap;
11130 spec->num_adc_nids++;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020011131 }
Takashi Iwai4953550a2009-06-30 15:28:30 +020011132 spec->adc_nids = spec->private_adc_nids;
11133 spec->capsrc_nids = spec->private_capsrc_nids;
Kailang Yang2f893282008-05-27 12:14:47 +020011134 }
11135
Takashi Iwaib59bdf32009-08-11 09:47:30 +020011136 set_capture_mixer(codec);
Kailang Yangda00c242010-03-19 11:23:45 +010011137
Takashi Iwaidc1eae22010-07-29 15:30:02 +020011138 if (has_cdefine_beep(codec))
Kailang Yangda00c242010-03-19 11:23:45 +010011139 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011140
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010011141 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwai7fa90e82010-04-12 08:49:00 +020011142
Takashi Iwai2134ea42008-01-10 16:53:55 +010011143 spec->vmaster_nid = 0x0c;
11144
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011145 codec->patch_ops = alc_patch_ops;
Takashi Iwai4953550a2009-06-30 15:28:30 +020011146 if (board_config == ALC882_AUTO)
11147 spec->init_hook = alc882_auto_init;
Kailang Yangbf1b0222010-10-21 08:49:56 +020011148
11149 alc_init_jacks(codec);
Takashi Iwaicb53c622007-08-10 17:21:45 +020011150#ifdef CONFIG_SND_HDA_POWER_SAVE
11151 if (!spec->loopback.amplist)
Takashi Iwai4953550a2009-06-30 15:28:30 +020011152 spec->loopback.amplist = alc882_loopbacks;
Takashi Iwaicb53c622007-08-10 17:21:45 +020011153#endif
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011154
11155 return 0;
11156}
11157
Takashi Iwai4953550a2009-06-30 15:28:30 +020011158
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011159/*
Kailang Yangdf694da2005-12-05 19:42:22 +010011160 * ALC262 support
11161 */
11162
11163#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
11164#define ALC262_DIGIN_NID ALC880_DIGIN_NID
11165
11166#define alc262_dac_nids alc260_dac_nids
11167#define alc262_adc_nids alc882_adc_nids
11168#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +010011169#define alc262_capsrc_nids alc882_capsrc_nids
11170#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +010011171
11172#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +010011173#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +010011174
Kailang Yang4e555fe2008-08-26 13:05:55 +020011175static hda_nid_t alc262_dmic_adc_nids[1] = {
11176 /* ADC0 */
11177 0x09
11178};
11179
11180static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
11181
Kailang Yangdf694da2005-12-05 19:42:22 +010011182static struct snd_kcontrol_new alc262_base_mixer[] = {
11183 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11184 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11185 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11186 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11187 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11188 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11189 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11190 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011191 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011192 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11193 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011194 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011195 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
11196 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11197 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
11198 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011199 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +010011200};
11201
Takashi Iwaice875f02008-01-28 18:17:43 +010011202/* update HP, line and mono-out pins according to the master switch */
11203static void alc262_hp_master_update(struct hda_codec *codec)
11204{
11205 struct alc_spec *spec = codec->spec;
11206 int val = spec->master_sw;
11207
11208 /* HP & line-out */
11209 snd_hda_codec_write_cache(codec, 0x1b, 0,
11210 AC_VERB_SET_PIN_WIDGET_CONTROL,
11211 val ? PIN_HP : 0);
11212 snd_hda_codec_write_cache(codec, 0x15, 0,
11213 AC_VERB_SET_PIN_WIDGET_CONTROL,
11214 val ? PIN_HP : 0);
11215 /* mono (speaker) depending on the HP jack sense */
11216 val = val && !spec->jack_present;
11217 snd_hda_codec_write_cache(codec, 0x16, 0,
11218 AC_VERB_SET_PIN_WIDGET_CONTROL,
11219 val ? PIN_OUT : 0);
11220}
11221
11222static void alc262_hp_bpc_automute(struct hda_codec *codec)
11223{
11224 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080011225
11226 spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
Takashi Iwaice875f02008-01-28 18:17:43 +010011227 alc262_hp_master_update(codec);
11228}
11229
11230static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
11231{
11232 if ((res >> 26) != ALC880_HP_EVENT)
11233 return;
11234 alc262_hp_bpc_automute(codec);
11235}
11236
11237static void alc262_hp_wildwest_automute(struct hda_codec *codec)
11238{
11239 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080011240
11241 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaice875f02008-01-28 18:17:43 +010011242 alc262_hp_master_update(codec);
11243}
11244
11245static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
11246 unsigned int res)
11247{
11248 if ((res >> 26) != ALC880_HP_EVENT)
11249 return;
11250 alc262_hp_wildwest_automute(codec);
11251}
11252
Takashi Iwaib72519b2009-05-08 14:31:55 +020011253#define alc262_hp_master_sw_get alc260_hp_master_sw_get
Takashi Iwaice875f02008-01-28 18:17:43 +010011254
11255static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
11256 struct snd_ctl_elem_value *ucontrol)
11257{
11258 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11259 struct alc_spec *spec = codec->spec;
11260 int val = !!*ucontrol->value.integer.value;
11261
11262 if (val == spec->master_sw)
11263 return 0;
11264 spec->master_sw = val;
11265 alc262_hp_master_update(codec);
11266 return 1;
11267}
11268
Takashi Iwaib72519b2009-05-08 14:31:55 +020011269#define ALC262_HP_MASTER_SWITCH \
11270 { \
11271 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
11272 .name = "Master Playback Switch", \
11273 .info = snd_ctl_boolean_mono_info, \
11274 .get = alc262_hp_master_sw_get, \
11275 .put = alc262_hp_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011276 }, \
11277 { \
11278 .iface = NID_MAPPING, \
11279 .name = "Master Playback Switch", \
11280 .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \
Takashi Iwaib72519b2009-05-08 14:31:55 +020011281 }
11282
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011283
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011284static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020011285 ALC262_HP_MASTER_SWITCH,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011286 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11287 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11288 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010011289 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
11290 HDA_OUTPUT),
11291 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
11292 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011293 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11294 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011295 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011296 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11297 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011298 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011299 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11300 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11301 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11302 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011303 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
11304 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
11305 { } /* end */
11306};
11307
Kailang Yangcd7509a2007-01-26 18:33:17 +010011308static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020011309 ALC262_HP_MASTER_SWITCH,
Kailang Yangcd7509a2007-01-26 18:33:17 +010011310 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11311 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
11312 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11313 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010011314 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
11315 HDA_OUTPUT),
11316 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
11317 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011318 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
11319 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011320 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011321 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
11322 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
11323 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11324 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011325 { } /* end */
11326};
11327
11328static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
11329 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11330 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011331 HDA_CODEC_VOLUME("Rear Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011332 { } /* end */
11333};
11334
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011335/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011336static void alc262_hp_t5735_setup(struct hda_codec *codec)
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011337{
11338 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011339
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011340 spec->autocfg.hp_pins[0] = 0x15;
Takashi Iwaidc99be42010-01-20 08:35:06 +010011341 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011342}
11343
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011344static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010011345 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11346 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011347 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11348 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11349 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11350 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011351 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011352 { } /* end */
11353};
11354
11355static struct hda_verb alc262_hp_t5735_verbs[] = {
11356 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11357 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11358
11359 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11360 { }
11361};
11362
Kailang Yang8c427222008-01-10 13:03:59 +010011363static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +010011364 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11365 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010011366 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
11367 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010011368 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
11369 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
11370 { } /* end */
11371};
11372
11373static struct hda_verb alc262_hp_rp5700_verbs[] = {
11374 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11375 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11376 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11377 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11378 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11379 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11380 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11381 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11382 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
11383 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
11384 {}
11385};
11386
11387static struct hda_input_mux alc262_hp_rp5700_capture_source = {
11388 .num_items = 1,
11389 .items = {
11390 { "Line", 0x1 },
11391 },
11392};
11393
Takashi Iwai42171c12009-05-08 14:11:43 +020011394/* bind hp and internal speaker mute (with plug check) as master switch */
11395static void alc262_hippo_master_update(struct hda_codec *codec)
11396{
11397 struct alc_spec *spec = codec->spec;
11398 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
11399 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
11400 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
11401 unsigned int mute;
11402
11403 /* HP */
11404 mute = spec->master_sw ? 0 : HDA_AMP_MUTE;
11405 snd_hda_codec_amp_stereo(codec, hp_nid, HDA_OUTPUT, 0,
11406 HDA_AMP_MUTE, mute);
11407 /* mute internal speaker per jack sense */
11408 if (spec->jack_present)
11409 mute = HDA_AMP_MUTE;
11410 if (line_nid)
11411 snd_hda_codec_amp_stereo(codec, line_nid, HDA_OUTPUT, 0,
11412 HDA_AMP_MUTE, mute);
11413 if (speaker_nid && speaker_nid != line_nid)
11414 snd_hda_codec_amp_stereo(codec, speaker_nid, HDA_OUTPUT, 0,
11415 HDA_AMP_MUTE, mute);
11416}
11417
11418#define alc262_hippo_master_sw_get alc262_hp_master_sw_get
11419
11420static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol,
11421 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai0724ea22007-08-23 00:31:43 +020011422{
11423 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Takashi Iwai42171c12009-05-08 14:11:43 +020011424 struct alc_spec *spec = codec->spec;
11425 int val = !!*ucontrol->value.integer.value;
Takashi Iwai0724ea22007-08-23 00:31:43 +020011426
Takashi Iwai42171c12009-05-08 14:11:43 +020011427 if (val == spec->master_sw)
11428 return 0;
11429 spec->master_sw = val;
11430 alc262_hippo_master_update(codec);
11431 return 1;
Takashi Iwai0724ea22007-08-23 00:31:43 +020011432}
Takashi Iwai5b319542007-07-26 11:49:22 +020011433
Takashi Iwai42171c12009-05-08 14:11:43 +020011434#define ALC262_HIPPO_MASTER_SWITCH \
11435 { \
11436 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
11437 .name = "Master Playback Switch", \
11438 .info = snd_ctl_boolean_mono_info, \
11439 .get = alc262_hippo_master_sw_get, \
11440 .put = alc262_hippo_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011441 }, \
11442 { \
11443 .iface = NID_MAPPING, \
11444 .name = "Master Playback Switch", \
11445 .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \
11446 (SUBDEV_SPEAKER(0) << 16), \
Takashi Iwai42171c12009-05-08 14:11:43 +020011447 }
11448
11449static struct snd_kcontrol_new alc262_hippo_mixer[] = {
11450 ALC262_HIPPO_MASTER_SWITCH,
11451 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11452 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11453 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11454 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11455 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11456 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11457 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011458 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011459 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11460 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011461 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011462 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11463 { } /* end */
11464};
11465
11466static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
11467 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11468 ALC262_HIPPO_MASTER_SWITCH,
11469 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11470 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11471 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11472 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11473 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11474 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011475 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011476 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11477 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011478 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011479 { } /* end */
11480};
11481
11482/* mute/unmute internal speaker according to the hp jack and mute state */
11483static void alc262_hippo_automute(struct hda_codec *codec)
11484{
11485 struct alc_spec *spec = codec->spec;
11486 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
Takashi Iwai42171c12009-05-08 14:11:43 +020011487
Wu Fengguang864f92b2009-11-18 12:38:02 +080011488 spec->jack_present = snd_hda_jack_detect(codec, hp_nid);
Takashi Iwai42171c12009-05-08 14:11:43 +020011489 alc262_hippo_master_update(codec);
11490}
11491
11492static void alc262_hippo_unsol_event(struct hda_codec *codec, unsigned int res)
11493{
11494 if ((res >> 26) != ALC880_HP_EVENT)
11495 return;
11496 alc262_hippo_automute(codec);
11497}
11498
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011499static void alc262_hippo_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020011500{
11501 struct alc_spec *spec = codec->spec;
11502
11503 spec->autocfg.hp_pins[0] = 0x15;
11504 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai42171c12009-05-08 14:11:43 +020011505}
11506
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011507static void alc262_hippo1_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020011508{
11509 struct alc_spec *spec = codec->spec;
11510
11511 spec->autocfg.hp_pins[0] = 0x1b;
11512 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai42171c12009-05-08 14:11:43 +020011513}
11514
11515
Kailang Yang272a5272007-05-14 11:00:38 +020011516static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +020011517 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011518 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang272a5272007-05-14 11:00:38 +020011519 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11520 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11521 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11522 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11523 { } /* end */
11524};
11525
Kailang Yang83c34212007-07-05 11:43:05 +020011526static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011527 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11528 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang83c34212007-07-05 11:43:05 +020011529 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11530 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11531 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11532 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11533 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11534 { } /* end */
11535};
Kailang Yang272a5272007-05-14 11:00:38 +020011536
Tony Vroonba340e82009-02-02 19:01:30 +000011537static struct snd_kcontrol_new alc262_tyan_mixer[] = {
11538 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11539 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
11540 HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
11541 HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT),
11542 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11543 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11544 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11545 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011546 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tony Vroonba340e82009-02-02 19:01:30 +000011547 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11548 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011549 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Tony Vroonba340e82009-02-02 19:01:30 +000011550 { } /* end */
11551};
11552
11553static struct hda_verb alc262_tyan_verbs[] = {
11554 /* Headphone automute */
11555 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11556 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11557 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11558
11559 /* P11 AUX_IN, white 4-pin connector */
11560 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11561 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
11562 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
11563 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
11564
11565 {}
11566};
11567
11568/* unsolicited event for HP jack sensing */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011569static void alc262_tyan_setup(struct hda_codec *codec)
Tony Vroonba340e82009-02-02 19:01:30 +000011570{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011571 struct alc_spec *spec = codec->spec;
Tony Vroonba340e82009-02-02 19:01:30 +000011572
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011573 spec->autocfg.hp_pins[0] = 0x1b;
11574 spec->autocfg.speaker_pins[0] = 0x15;
Tony Vroonba340e82009-02-02 19:01:30 +000011575}
11576
Tony Vroonba340e82009-02-02 19:01:30 +000011577
Kailang Yangdf694da2005-12-05 19:42:22 +010011578#define alc262_capture_mixer alc882_capture_mixer
11579#define alc262_capture_alt_mixer alc882_capture_alt_mixer
11580
11581/*
11582 * generic initialization of ADC, input mixers and output mixers
11583 */
11584static struct hda_verb alc262_init_verbs[] = {
11585 /*
11586 * Unmute ADC0-2 and set the default input to mic-in
11587 */
11588 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11589 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11590 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11591 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11592 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11593 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11594
Takashi Iwaicb53c622007-08-10 17:21:45 +020011595 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010011596 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011597 * Note: PASD motherboards uses the Line In 2 as the input for
11598 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010011599 */
11600 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011601 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11602 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11603 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11604 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11605 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011606
11607 /*
11608 * Set up output mixers (0x0c - 0x0e)
11609 */
11610 /* set vol=0 to output mixers */
11611 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11612 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11613 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11614 /* set up input amps for analog loopback */
11615 /* Amp Indices: DAC = 0, mixer = 1 */
11616 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11617 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11618 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11619 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11620 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11621 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11622
11623 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11624 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11625 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11626 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11627 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11628 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11629
11630 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11631 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11632 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11633 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11634 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Kailang Yangea1fb292008-08-26 12:58:38 +020011635
Kailang Yangdf694da2005-12-05 19:42:22 +010011636 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11637 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Kailang Yangea1fb292008-08-26 12:58:38 +020011638
Kailang Yangdf694da2005-12-05 19:42:22 +010011639 /* FIXME: use matrix-type input source selection */
11640 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
11641 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
11642 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11643 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11644 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11645 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11646 /* Input mixer2 */
11647 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11648 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11649 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11650 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11651 /* Input mixer3 */
11652 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11653 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11654 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011655 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +010011656
11657 { }
11658};
11659
Kailang Yang4e555fe2008-08-26 13:05:55 +020011660static struct hda_verb alc262_eapd_verbs[] = {
11661 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
11662 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
11663 { }
11664};
11665
Kailang Yangccc656c2006-10-17 12:32:26 +020011666static struct hda_verb alc262_hippo1_unsol_verbs[] = {
11667 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11668 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11669 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11670
11671 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11672 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11673 {}
11674};
11675
Kailang Yang272a5272007-05-14 11:00:38 +020011676static struct hda_verb alc262_sony_unsol_verbs[] = {
11677 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11678 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11679 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
11680
11681 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11682 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +090011683 {}
Kailang Yang272a5272007-05-14 11:00:38 +020011684};
11685
Kailang Yang4e555fe2008-08-26 13:05:55 +020011686static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
11687 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11688 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11689 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11690 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11691 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang4e555fe2008-08-26 13:05:55 +020011692 { } /* end */
11693};
11694
11695static struct hda_verb alc262_toshiba_s06_verbs[] = {
11696 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11697 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11698 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11699 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11700 {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
11701 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11702 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11703 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11704 {}
11705};
11706
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011707static void alc262_toshiba_s06_setup(struct hda_codec *codec)
Kailang Yang4e555fe2008-08-26 13:05:55 +020011708{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011709 struct alc_spec *spec = codec->spec;
11710
11711 spec->autocfg.hp_pins[0] = 0x15;
11712 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011713 spec->ext_mic.pin = 0x18;
11714 spec->ext_mic.mux_idx = 0;
11715 spec->int_mic.pin = 0x12;
11716 spec->int_mic.mux_idx = 9;
11717 spec->auto_mic = 1;
Kailang Yang4e555fe2008-08-26 13:05:55 +020011718}
11719
Takashi Iwai834be882006-03-01 14:16:17 +010011720/*
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011721 * nec model
11722 * 0x15 = headphone
11723 * 0x16 = internal speaker
11724 * 0x18 = external mic
11725 */
11726
11727static struct snd_kcontrol_new alc262_nec_mixer[] = {
11728 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
11729 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
11730
11731 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11732 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011733 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011734
11735 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11736 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11737 { } /* end */
11738};
11739
11740static struct hda_verb alc262_nec_verbs[] = {
11741 /* Unmute Speaker */
11742 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11743
11744 /* Headphone */
11745 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11746 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11747
11748 /* External mic to headphone */
11749 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11750 /* External mic to speaker */
11751 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11752 {}
11753};
11754
11755/*
Takashi Iwai834be882006-03-01 14:16:17 +010011756 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +010011757 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
11758 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +010011759 */
11760
11761#define ALC_HP_EVENT 0x37
11762
11763static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
11764 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11765 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +010011766 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11767 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +010011768 {}
11769};
11770
Jiang zhe0e31daf2008-03-20 12:12:39 +010011771static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
11772 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11773 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11774 {}
11775};
11776
Daniel T Chene2595322009-12-19 18:19:02 -050011777static struct hda_verb alc262_lenovo_3000_init_verbs[] = {
11778 /* Front Mic pin: input vref at 50% */
11779 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
11780 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11781 {}
11782};
11783
Takashi Iwai834be882006-03-01 14:16:17 +010011784static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011785 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +010011786 .items = {
11787 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +010011788 { "Internal Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +010011789 { "CD", 0x4 },
11790 },
11791};
11792
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011793static struct hda_input_mux alc262_HP_capture_source = {
11794 .num_items = 5,
11795 .items = {
11796 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +020011797 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011798 { "Line", 0x2 },
11799 { "CD", 0x4 },
11800 { "AUX IN", 0x6 },
11801 },
11802};
11803
zhejiangaccbe492007-08-31 12:36:05 +020011804static struct hda_input_mux alc262_HP_D7000_capture_source = {
11805 .num_items = 4,
11806 .items = {
11807 { "Mic", 0x0 },
11808 { "Front Mic", 0x2 },
11809 { "Line", 0x1 },
11810 { "CD", 0x4 },
11811 },
11812};
11813
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011814/* mute/unmute internal speaker according to the hp jacks and mute state */
Takashi Iwai834be882006-03-01 14:16:17 +010011815static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
11816{
11817 struct alc_spec *spec = codec->spec;
11818 unsigned int mute;
11819
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011820 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011821 spec->jack_present = snd_hda_jack_detect(codec, 0x14) ||
11822 snd_hda_jack_detect(codec, 0x1b);
Takashi Iwai834be882006-03-01 14:16:17 +010011823 spec->sense_updated = 1;
11824 }
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011825 /* unmute internal speaker only if both HPs are unplugged and
11826 * master switch is on
11827 */
11828 if (spec->jack_present)
11829 mute = HDA_AMP_MUTE;
11830 else
Takashi Iwai834be882006-03-01 14:16:17 +010011831 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011832 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
11833 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +010011834}
11835
11836/* unsolicited event for HP jack sensing */
11837static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
11838 unsigned int res)
11839{
11840 if ((res >> 26) != ALC_HP_EVENT)
11841 return;
11842 alc262_fujitsu_automute(codec, 1);
11843}
11844
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011845static void alc262_fujitsu_init_hook(struct hda_codec *codec)
11846{
11847 alc262_fujitsu_automute(codec, 1);
11848}
11849
Takashi Iwai834be882006-03-01 14:16:17 +010011850/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +020011851static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
11852 .ops = &snd_hda_bind_vol,
11853 .values = {
11854 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
11855 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
11856 0
11857 },
11858};
Takashi Iwai834be882006-03-01 14:16:17 +010011859
Jiang zhe0e31daf2008-03-20 12:12:39 +010011860/* mute/unmute internal speaker according to the hp jack and mute state */
11861static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
11862{
11863 struct alc_spec *spec = codec->spec;
11864 unsigned int mute;
11865
11866 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011867 spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
Jiang zhe0e31daf2008-03-20 12:12:39 +010011868 spec->sense_updated = 1;
11869 }
11870 if (spec->jack_present) {
11871 /* mute internal speaker */
11872 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11873 HDA_AMP_MUTE, HDA_AMP_MUTE);
11874 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
11875 HDA_AMP_MUTE, HDA_AMP_MUTE);
11876 } else {
11877 /* unmute internal speaker if necessary */
11878 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
11879 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11880 HDA_AMP_MUTE, mute);
11881 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
11882 HDA_AMP_MUTE, mute);
11883 }
11884}
11885
11886/* unsolicited event for HP jack sensing */
11887static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
11888 unsigned int res)
11889{
11890 if ((res >> 26) != ALC_HP_EVENT)
11891 return;
11892 alc262_lenovo_3000_automute(codec, 1);
11893}
11894
Takashi Iwai8de56b72009-07-24 16:51:47 +020011895static int amp_stereo_mute_update(struct hda_codec *codec, hda_nid_t nid,
11896 int dir, int idx, long *valp)
11897{
11898 int i, change = 0;
11899
11900 for (i = 0; i < 2; i++, valp++)
11901 change |= snd_hda_codec_amp_update(codec, nid, i, dir, idx,
11902 HDA_AMP_MUTE,
11903 *valp ? 0 : HDA_AMP_MUTE);
11904 return change;
11905}
11906
Takashi Iwai834be882006-03-01 14:16:17 +010011907/* bind hp and internal speaker mute (with plug check) */
11908static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
11909 struct snd_ctl_elem_value *ucontrol)
11910{
11911 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11912 long *valp = ucontrol->value.integer.value;
11913 int change;
11914
Takashi Iwai8de56b72009-07-24 16:51:47 +020011915 change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
11916 change |= amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
Takashi Iwai82beb8f2007-08-10 17:09:26 +020011917 if (change)
11918 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +010011919 return change;
11920}
11921
11922static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +020011923 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +010011924 {
11925 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11926 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010011927 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwai834be882006-03-01 14:16:17 +010011928 .info = snd_hda_mixer_amp_switch_info,
11929 .get = snd_hda_mixer_amp_switch_get,
11930 .put = alc262_fujitsu_master_sw_put,
11931 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11932 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011933 {
11934 .iface = NID_MAPPING,
11935 .name = "Master Playback Switch",
11936 .private_value = 0x1b,
11937 },
Takashi Iwai834be882006-03-01 14:16:17 +010011938 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11939 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011940 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010011941 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11942 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011943 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +010011944 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11945 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010011946 { } /* end */
11947};
11948
Jiang zhe0e31daf2008-03-20 12:12:39 +010011949/* bind hp and internal speaker mute (with plug check) */
11950static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
11951 struct snd_ctl_elem_value *ucontrol)
11952{
11953 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11954 long *valp = ucontrol->value.integer.value;
11955 int change;
11956
Takashi Iwai8de56b72009-07-24 16:51:47 +020011957 change = amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
Jiang zhe0e31daf2008-03-20 12:12:39 +010011958 if (change)
11959 alc262_lenovo_3000_automute(codec, 0);
11960 return change;
11961}
11962
11963static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
11964 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
11965 {
11966 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11967 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010011968 .subdevice = HDA_SUBDEV_AMP_FLAG,
Jiang zhe0e31daf2008-03-20 12:12:39 +010011969 .info = snd_hda_mixer_amp_switch_info,
11970 .get = snd_hda_mixer_amp_switch_get,
11971 .put = alc262_lenovo_3000_master_sw_put,
11972 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
11973 },
11974 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11975 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011976 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhe0e31daf2008-03-20 12:12:39 +010011977 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11978 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011979 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +010011980 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11981 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe0e31daf2008-03-20 12:12:39 +010011982 { } /* end */
11983};
11984
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011985static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
11986 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai42171c12009-05-08 14:11:43 +020011987 ALC262_HIPPO_MASTER_SWITCH,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011988 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11989 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011990 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011991 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11992 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011993 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011994 { } /* end */
11995};
11996
Takashi Iwai304dcaa2006-07-25 14:51:16 +020011997/* additional init verbs for Benq laptops */
11998static struct hda_verb alc262_EAPD_verbs[] = {
11999 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
12000 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
12001 {}
12002};
12003
Kailang Yang83c34212007-07-05 11:43:05 +020012004static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
12005 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12006 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12007
12008 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
12009 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
12010 {}
12011};
12012
Tobin Davisf651b502007-10-26 12:40:47 +020012013/* Samsung Q1 Ultra Vista model setup */
12014static struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012015 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
12016 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020012017 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
12018 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010012019 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
12020 HDA_CODEC_VOLUME("Headphone Mic Boost Volume", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020012021 { } /* end */
12022};
12023
12024static struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012025 /* output mixer */
12026 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12027 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12028 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12029 /* speaker */
12030 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12031 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12032 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12033 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
12034 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +020012035 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012036 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12037 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12038 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12039 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12040 /* internal mic */
12041 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12042 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12043 /* ADC, choose mic */
12044 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12045 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12046 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12047 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12048 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12049 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12050 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12051 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
12052 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
12053 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +020012054 {}
12055};
12056
Tobin Davisf651b502007-10-26 12:40:47 +020012057/* mute/unmute internal speaker according to the hp jack and mute state */
12058static void alc262_ultra_automute(struct hda_codec *codec)
12059{
12060 struct alc_spec *spec = codec->spec;
12061 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +020012062
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012063 mute = 0;
12064 /* auto-mute only when HP is used as HP */
12065 if (!spec->cur_mux[0]) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080012066 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012067 if (spec->jack_present)
12068 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +020012069 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012070 /* mute/unmute internal speaker */
12071 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
12072 HDA_AMP_MUTE, mute);
12073 /* mute/unmute HP */
12074 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
12075 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +020012076}
12077
12078/* unsolicited event for HP jack sensing */
12079static void alc262_ultra_unsol_event(struct hda_codec *codec,
12080 unsigned int res)
12081{
12082 if ((res >> 26) != ALC880_HP_EVENT)
12083 return;
12084 alc262_ultra_automute(codec);
12085}
12086
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012087static struct hda_input_mux alc262_ultra_capture_source = {
12088 .num_items = 2,
12089 .items = {
12090 { "Mic", 0x1 },
12091 { "Headphone", 0x7 },
12092 },
12093};
12094
12095static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
12096 struct snd_ctl_elem_value *ucontrol)
12097{
12098 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
12099 struct alc_spec *spec = codec->spec;
12100 int ret;
12101
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010012102 ret = alc_mux_enum_put(kcontrol, ucontrol);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012103 if (!ret)
12104 return 0;
12105 /* reprogram the HP pin as mic or HP according to the input source */
12106 snd_hda_codec_write_cache(codec, 0x15, 0,
12107 AC_VERB_SET_PIN_WIDGET_CONTROL,
12108 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
12109 alc262_ultra_automute(codec); /* mute/unmute HP */
12110 return ret;
12111}
12112
12113static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
12114 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
12115 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
12116 {
12117 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12118 .name = "Capture Source",
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010012119 .info = alc_mux_enum_info,
12120 .get = alc_mux_enum_get,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012121 .put = alc262_ultra_mux_enum_put,
12122 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010012123 {
12124 .iface = NID_MAPPING,
12125 .name = "Capture Source",
12126 .private_value = 0x15,
12127 },
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012128 { } /* end */
12129};
12130
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012131/* We use two mixers depending on the output pin; 0x16 is a mono output
12132 * and thus it's bound with a different mixer.
12133 * This function returns which mixer amp should be used.
12134 */
12135static int alc262_check_volbit(hda_nid_t nid)
12136{
12137 if (!nid)
12138 return 0;
12139 else if (nid == 0x16)
12140 return 2;
12141 else
12142 return 1;
12143}
12144
12145static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai033688a2010-09-08 15:47:09 +020012146 const char *pfx, int *vbits, int idx)
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012147{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012148 unsigned long val;
12149 int vbit;
12150
12151 vbit = alc262_check_volbit(nid);
12152 if (!vbit)
12153 return 0;
12154 if (*vbits & vbit) /* a volume control for this mixer already there */
12155 return 0;
12156 *vbits |= vbit;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012157 if (vbit == 2)
12158 val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT);
12159 else
12160 val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT);
Takashi Iwai033688a2010-09-08 15:47:09 +020012161 return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012162}
12163
12164static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai033688a2010-09-08 15:47:09 +020012165 const char *pfx, int idx)
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012166{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012167 unsigned long val;
12168
12169 if (!nid)
12170 return 0;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012171 if (nid == 0x16)
12172 val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
12173 else
12174 val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
Takashi Iwai033688a2010-09-08 15:47:09 +020012175 return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012176}
12177
Kailang Yangdf694da2005-12-05 19:42:22 +010012178/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012179static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
12180 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010012181{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012182 const char *pfx;
12183 int vbits;
Takashi Iwai033688a2010-09-08 15:47:09 +020012184 int i, err;
Kailang Yangdf694da2005-12-05 19:42:22 +010012185
12186 spec->multiout.num_dacs = 1; /* only use one dac */
12187 spec->multiout.dac_nids = spec->private_dac_nids;
12188 spec->multiout.dac_nids[0] = 2;
12189
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010012190 pfx = alc_get_line_out_pfx(cfg, true);
12191 if (!pfx)
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012192 pfx = "Front";
Takashi Iwai033688a2010-09-08 15:47:09 +020012193 for (i = 0; i < 2; i++) {
12194 err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[i], pfx, i);
12195 if (err < 0)
12196 return err;
12197 if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
12198 err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[i],
12199 "Speaker", i);
12200 if (err < 0)
12201 return err;
12202 }
12203 if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
12204 err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[i],
12205 "Headphone", i);
12206 if (err < 0)
12207 return err;
12208 }
12209 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012210
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012211 vbits = alc262_check_volbit(cfg->line_out_pins[0]) |
12212 alc262_check_volbit(cfg->speaker_pins[0]) |
12213 alc262_check_volbit(cfg->hp_pins[0]);
12214 if (vbits == 1 || vbits == 2)
12215 pfx = "Master"; /* only one mixer is used */
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012216 vbits = 0;
Takashi Iwai033688a2010-09-08 15:47:09 +020012217 for (i = 0; i < 2; i++) {
12218 err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[i], pfx,
12219 &vbits, i);
12220 if (err < 0)
12221 return err;
12222 if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
12223 err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[i],
12224 "Speaker", &vbits, i);
12225 if (err < 0)
12226 return err;
12227 }
12228 if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
12229 err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[i],
12230 "Headphone", &vbits, i);
12231 if (err < 0)
12232 return err;
12233 }
12234 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012235 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +010012236}
12237
Takashi Iwai05f5f472009-08-25 13:10:18 +020012238#define alc262_auto_create_input_ctls \
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +010012239 alc882_auto_create_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +010012240
12241/*
12242 * generic initialization of ADC, input mixers and output mixers
12243 */
12244static struct hda_verb alc262_volume_init_verbs[] = {
12245 /*
12246 * Unmute ADC0-2 and set the default input to mic-in
12247 */
12248 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
12249 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12250 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12251 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12252 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12253 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12254
Takashi Iwaicb53c622007-08-10 17:21:45 +020012255 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010012256 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012257 * Note: PASD motherboards uses the Line In 2 as the input for
12258 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010012259 */
12260 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012261 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12262 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12263 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12264 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12265 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012266
12267 /*
12268 * Set up output mixers (0x0c - 0x0f)
12269 */
12270 /* set vol=0 to output mixers */
12271 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12272 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12273 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yangea1fb292008-08-26 12:58:38 +020012274
Kailang Yangdf694da2005-12-05 19:42:22 +010012275 /* set up input amps for analog loopback */
12276 /* Amp Indices: DAC = 0, mixer = 1 */
12277 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12278 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12279 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12280 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12281 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12282 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12283
12284 /* FIXME: use matrix-type input source selection */
12285 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
12286 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
12287 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12288 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12289 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12290 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12291 /* Input mixer2 */
12292 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12293 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12294 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12295 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12296 /* Input mixer3 */
12297 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12298 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12299 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12300 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12301
12302 { }
12303};
12304
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012305static struct hda_verb alc262_HP_BPC_init_verbs[] = {
12306 /*
12307 * Unmute ADC0-2 and set the default input to mic-in
12308 */
12309 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
12310 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12311 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12312 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12313 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12314 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12315
Takashi Iwaicb53c622007-08-10 17:21:45 +020012316 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012317 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012318 * Note: PASD motherboards uses the Line In 2 as the input for
12319 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012320 */
12321 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012322 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12323 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12324 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12325 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12326 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12327 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12328 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012329
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012330 /*
12331 * Set up output mixers (0x0c - 0x0e)
12332 */
12333 /* set vol=0 to output mixers */
12334 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12335 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12336 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12337
12338 /* set up input amps for analog loopback */
12339 /* Amp Indices: DAC = 0, mixer = 1 */
12340 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12341 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12342 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12343 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12344 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12345 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12346
Takashi Iwaice875f02008-01-28 18:17:43 +010012347 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012348 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12349 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12350
12351 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12352 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12353
12354 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12355 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12356
12357 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12358 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12359 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12360 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12361 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12362
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012363 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012364 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12365 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012366 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012367 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12368 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12369
12370
12371 /* FIXME: use matrix-type input source selection */
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012372 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */
12373 /* Input mixer1: only unmute Mic */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012374 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012375 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12376 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12377 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12378 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12379 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12380 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12381 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12382 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012383 /* Input mixer2 */
12384 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012385 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12386 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12387 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12388 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12389 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12390 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12391 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12392 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012393 /* Input mixer3 */
12394 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012395 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12396 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12397 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12398 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12399 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12400 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12401 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12402 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012403
Takashi Iwaice875f02008-01-28 18:17:43 +010012404 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12405
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012406 { }
12407};
12408
Kailang Yangcd7509a2007-01-26 18:33:17 +010012409static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
12410 /*
12411 * Unmute ADC0-2 and set the default input to mic-in
12412 */
12413 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
12414 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12415 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12416 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12417 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12418 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12419
Takashi Iwaicb53c622007-08-10 17:21:45 +020012420 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +010012421 * mixer widget
12422 * Note: PASD motherboards uses the Line In 2 as the input for front
12423 * panel mic (mic 2)
12424 */
12425 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012426 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12427 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12428 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12429 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12430 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12431 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12432 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
12433 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +010012434 /*
12435 * Set up output mixers (0x0c - 0x0e)
12436 */
12437 /* set vol=0 to output mixers */
12438 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12439 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12440 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12441
12442 /* set up input amps for analog loopback */
12443 /* Amp Indices: DAC = 0, mixer = 1 */
12444 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12445 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12446 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12447 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12448 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12449 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12450
12451
12452 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
12453 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
12454 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
12455 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
12456 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
12457 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
12458 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
12459
12460 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12461 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12462
12463 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12464 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12465
12466 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
12467 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12468 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12469 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
12470 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12471 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12472
12473 /* FIXME: use matrix-type input source selection */
12474 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
12475 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
12476 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
12477 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
12478 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
12479 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
12480 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
12481 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12482 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
12483 /* Input mixer2 */
12484 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12485 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
12486 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
12487 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
12488 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
12489 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12490 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
12491 /* Input mixer3 */
12492 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12493 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
12494 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
12495 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
12496 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
12497 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12498 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
12499
Takashi Iwaice875f02008-01-28 18:17:43 +010012500 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12501
Kailang Yangcd7509a2007-01-26 18:33:17 +010012502 { }
12503};
12504
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012505static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
12506
12507 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */
12508 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12509 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
12510
12511 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */
12512 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
12513 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
12514 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
12515
12516 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */
12517 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12518 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12519 {}
12520};
12521
Takashi Iwai18675e42010-09-08 15:55:44 +020012522/*
12523 * Pin config fixes
12524 */
12525enum {
12526 PINFIX_FSC_H270,
12527};
12528
12529static const struct alc_fixup alc262_fixups[] = {
12530 [PINFIX_FSC_H270] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010012531 .type = ALC_FIXUP_PINS,
12532 .v.pins = (const struct alc_pincfg[]) {
Takashi Iwai18675e42010-09-08 15:55:44 +020012533 { 0x14, 0x99130110 }, /* speaker */
12534 { 0x15, 0x0221142f }, /* front HP */
12535 { 0x1b, 0x0121141f }, /* rear HP */
12536 { }
12537 }
12538 },
Takashi Iwai18675e42010-09-08 15:55:44 +020012539};
12540
12541static struct snd_pci_quirk alc262_fixup_tbl[] = {
12542 SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270),
12543 {}
12544};
12545
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012546
Takashi Iwaicb53c622007-08-10 17:21:45 +020012547#ifdef CONFIG_SND_HDA_POWER_SAVE
12548#define alc262_loopbacks alc880_loopbacks
12549#endif
12550
Sasha Alexandrdef319f2009-06-16 16:00:15 -040012551/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012552#define alc262_pcm_analog_playback alc880_pcm_analog_playback
12553#define alc262_pcm_analog_capture alc880_pcm_analog_capture
12554#define alc262_pcm_digital_playback alc880_pcm_digital_playback
12555#define alc262_pcm_digital_capture alc880_pcm_digital_capture
12556
12557/*
12558 * BIOS auto configuration
12559 */
12560static int alc262_parse_auto_config(struct hda_codec *codec)
12561{
12562 struct alc_spec *spec = codec->spec;
12563 int err;
12564 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
12565
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012566 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12567 alc262_ignore);
12568 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012569 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012570 if (!spec->autocfg.line_outs) {
Takashi Iwai0852d7a2009-02-11 11:35:15 +010012571 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012572 spec->multiout.max_channels = 2;
12573 spec->no_analog = 1;
12574 goto dig_only;
12575 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012576 return 0; /* can't find valid BIOS pin config */
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012577 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012578 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
12579 if (err < 0)
12580 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020012581 err = alc262_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012582 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012583 return err;
12584
12585 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12586
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012587 dig_only:
Takashi Iwai757899a2010-07-30 10:48:14 +020012588 alc_auto_parse_digital(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012589
Takashi Iwai603c4012008-07-30 15:01:44 +020012590 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012591 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010012592
Takashi Iwaid88897e2008-10-31 15:01:37 +010012593 add_verb(spec, alc262_volume_init_verbs);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020012594 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020012595 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010012596
Takashi Iwai776e1842007-08-29 15:07:11 +020012597 err = alc_auto_add_mic_boost(codec);
12598 if (err < 0)
12599 return err;
12600
Kailang Yang6227cdc2010-02-25 08:36:52 +010012601 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020012602
Kailang Yangdf694da2005-12-05 19:42:22 +010012603 return 1;
12604}
12605
12606#define alc262_auto_init_multi_out alc882_auto_init_multi_out
12607#define alc262_auto_init_hp_out alc882_auto_init_hp_out
12608#define alc262_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaif511b012008-08-15 16:46:42 +020012609#define alc262_auto_init_input_src alc882_auto_init_input_src
Kailang Yangdf694da2005-12-05 19:42:22 +010012610
12611
12612/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012613static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010012614{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012615 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010012616 alc262_auto_init_multi_out(codec);
12617 alc262_auto_init_hp_out(codec);
12618 alc262_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020012619 alc262_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020012620 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012621 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020012622 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012623}
12624
12625/*
12626 * configuration and preset
12627 */
Takashi Iwaiea734962011-01-17 11:29:34 +010012628static const char * const alc262_models[ALC262_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012629 [ALC262_BASIC] = "basic",
12630 [ALC262_HIPPO] = "hippo",
12631 [ALC262_HIPPO_1] = "hippo_1",
12632 [ALC262_FUJITSU] = "fujitsu",
12633 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +010012634 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +010012635 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +010012636 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012637 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +020012638 [ALC262_BENQ_T31] = "benq-t31",
12639 [ALC262_SONY_ASSAMD] = "sony-assamd",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020012640 [ALC262_TOSHIBA_S06] = "toshiba-s06",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012641 [ALC262_TOSHIBA_RX1] = "toshiba-rx1",
Tobin Davisf651b502007-10-26 12:40:47 +020012642 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +010012643 [ALC262_LENOVO_3000] = "lenovo-3000",
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012644 [ALC262_NEC] = "nec",
Tony Vroonba340e82009-02-02 19:01:30 +000012645 [ALC262_TYAN] = "tyan",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012646 [ALC262_AUTO] = "auto",
12647};
12648
12649static struct snd_pci_quirk alc262_cfg_tbl[] = {
12650 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012651 SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
Takashi Iwaidea0a502009-02-09 17:14:52 +010012652 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
12653 ALC262_HP_BPC),
12654 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series",
12655 ALC262_HP_BPC),
Takashi Iwai5734a072011-01-19 17:07:12 +010012656 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1500, "HP z series",
12657 ALC262_HP_BPC),
Takashi Iwai53eff7e2009-02-27 17:49:44 +010012658 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
12659 ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012660 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012661 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012662 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012663 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012664 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012665 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012666 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012667 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012668 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
12669 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
12670 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012671 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
12672 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +010012673 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012674 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012675 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012676 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaibd6afe32009-03-04 11:30:25 +010012677 SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */
Takashi Iwai376b5082009-06-22 11:03:13 +020012678 SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06),
Daniel T Chen95491d92009-11-08 19:03:55 -050012679 SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO),
Takashi Iwai12929ba2009-11-17 15:58:35 +010012680 SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO),
Takashi Iwaic5b51652009-11-17 16:01:58 +010012681#if 0 /* disable the quirk since model=auto works better in recent versions */
Takashi Iwaif872a912009-02-26 00:57:01 +010012682 SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
12683 ALC262_SONY_ASSAMD),
Takashi Iwaic5b51652009-11-17 16:01:58 +010012684#endif
Akio Idehara36ca6e12008-06-09 22:57:40 +090012685 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012686 ALC262_TOSHIBA_RX1),
Kailang Yang80ffe862008-10-15 11:23:27 +020012687 SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012688 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +010012689 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Tony Vroonba340e82009-02-02 19:01:30 +000012690 SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
Takashi Iwaidea0a502009-02-09 17:14:52 +010012691 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1",
12692 ALC262_ULTRA),
Luke Yelavich3e420e72008-12-16 12:37:47 +110012693 SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
Jiang zhe0e31daf2008-03-20 12:12:39 +010012694 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012695 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +020012696 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012697 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +010012698 {}
12699};
12700
12701static struct alc_config_preset alc262_presets[] = {
12702 [ALC262_BASIC] = {
12703 .mixers = { alc262_base_mixer },
12704 .init_verbs = { alc262_init_verbs },
12705 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12706 .dac_nids = alc262_dac_nids,
12707 .hp_nid = 0x03,
12708 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12709 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +010012710 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +010012711 },
Kailang Yangccc656c2006-10-17 12:32:26 +020012712 [ALC262_HIPPO] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020012713 .mixers = { alc262_hippo_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020012714 .init_verbs = { alc262_init_verbs, alc_hp15_unsol_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020012715 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12716 .dac_nids = alc262_dac_nids,
12717 .hp_nid = 0x03,
12718 .dig_out_nid = ALC262_DIGOUT_NID,
12719 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12720 .channel_mode = alc262_modes,
12721 .input_mux = &alc262_capture_source,
12722 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012723 .setup = alc262_hippo_setup,
12724 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020012725 },
12726 [ALC262_HIPPO_1] = {
12727 .mixers = { alc262_hippo1_mixer },
12728 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
12729 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12730 .dac_nids = alc262_dac_nids,
12731 .hp_nid = 0x02,
12732 .dig_out_nid = ALC262_DIGOUT_NID,
12733 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12734 .channel_mode = alc262_modes,
12735 .input_mux = &alc262_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020012736 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012737 .setup = alc262_hippo1_setup,
12738 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020012739 },
Takashi Iwai834be882006-03-01 14:16:17 +010012740 [ALC262_FUJITSU] = {
12741 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020012742 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
12743 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +010012744 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12745 .dac_nids = alc262_dac_nids,
12746 .hp_nid = 0x03,
12747 .dig_out_nid = ALC262_DIGOUT_NID,
12748 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12749 .channel_mode = alc262_modes,
12750 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012751 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwaiebc7a402008-05-20 09:23:05 +020012752 .init_hook = alc262_fujitsu_init_hook,
Takashi Iwai834be882006-03-01 14:16:17 +010012753 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012754 [ALC262_HP_BPC] = {
12755 .mixers = { alc262_HP_BPC_mixer },
12756 .init_verbs = { alc262_HP_BPC_init_verbs },
12757 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12758 .dac_nids = alc262_dac_nids,
12759 .hp_nid = 0x03,
12760 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12761 .channel_mode = alc262_modes,
12762 .input_mux = &alc262_HP_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010012763 .unsol_event = alc262_hp_bpc_unsol_event,
12764 .init_hook = alc262_hp_bpc_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012765 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010012766 [ALC262_HP_BPC_D7000_WF] = {
12767 .mixers = { alc262_HP_BPC_WildWest_mixer },
12768 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
12769 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12770 .dac_nids = alc262_dac_nids,
12771 .hp_nid = 0x03,
12772 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12773 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020012774 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010012775 .unsol_event = alc262_hp_wildwest_unsol_event,
12776 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012777 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010012778 [ALC262_HP_BPC_D7000_WL] = {
12779 .mixers = { alc262_HP_BPC_WildWest_mixer,
12780 alc262_HP_BPC_WildWest_option_mixer },
12781 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
12782 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12783 .dac_nids = alc262_dac_nids,
12784 .hp_nid = 0x03,
12785 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12786 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020012787 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010012788 .unsol_event = alc262_hp_wildwest_unsol_event,
12789 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012790 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012791 [ALC262_HP_TC_T5735] = {
12792 .mixers = { alc262_hp_t5735_mixer },
12793 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_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 Iwaidc99be42010-01-20 08:35:06 +010012800 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012801 .setup = alc262_hp_t5735_setup,
Takashi Iwaidc99be42010-01-20 08:35:06 +010012802 .init_hook = alc_inithook,
Kailang Yang8c427222008-01-10 13:03:59 +010012803 },
12804 [ALC262_HP_RP5700] = {
12805 .mixers = { alc262_hp_rp5700_mixer },
12806 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
12807 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12808 .dac_nids = alc262_dac_nids,
12809 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12810 .channel_mode = alc262_modes,
12811 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012812 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +020012813 [ALC262_BENQ_ED8] = {
12814 .mixers = { alc262_base_mixer },
12815 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
12816 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12817 .dac_nids = alc262_dac_nids,
12818 .hp_nid = 0x03,
12819 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12820 .channel_mode = alc262_modes,
12821 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012822 },
Kailang Yang272a5272007-05-14 11:00:38 +020012823 [ALC262_SONY_ASSAMD] = {
12824 .mixers = { alc262_sony_mixer },
12825 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
12826 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12827 .dac_nids = alc262_dac_nids,
12828 .hp_nid = 0x02,
12829 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12830 .channel_mode = alc262_modes,
12831 .input_mux = &alc262_capture_source,
12832 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012833 .setup = alc262_hippo_setup,
12834 .init_hook = alc262_hippo_automute,
Kailang Yang83c34212007-07-05 11:43:05 +020012835 },
12836 [ALC262_BENQ_T31] = {
12837 .mixers = { alc262_benq_t31_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020012838 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs,
12839 alc_hp15_unsol_verbs },
Kailang Yang83c34212007-07-05 11:43:05 +020012840 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12841 .dac_nids = alc262_dac_nids,
12842 .hp_nid = 0x03,
12843 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12844 .channel_mode = alc262_modes,
12845 .input_mux = &alc262_capture_source,
12846 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012847 .setup = alc262_hippo_setup,
12848 .init_hook = alc262_hippo_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020012849 },
Tobin Davisf651b502007-10-26 12:40:47 +020012850 [ALC262_ULTRA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012851 .mixers = { alc262_ultra_mixer },
12852 .cap_mixer = alc262_ultra_capture_mixer,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012853 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +020012854 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12855 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +020012856 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12857 .channel_mode = alc262_modes,
12858 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012859 .adc_nids = alc262_adc_nids, /* ADC0 */
12860 .capsrc_nids = alc262_capsrc_nids,
12861 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +020012862 .unsol_event = alc262_ultra_unsol_event,
12863 .init_hook = alc262_ultra_automute,
12864 },
Jiang zhe0e31daf2008-03-20 12:12:39 +010012865 [ALC262_LENOVO_3000] = {
12866 .mixers = { alc262_lenovo_3000_mixer },
12867 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
Daniel T Chene2595322009-12-19 18:19:02 -050012868 alc262_lenovo_3000_unsol_verbs,
12869 alc262_lenovo_3000_init_verbs },
Jiang zhe0e31daf2008-03-20 12:12:39 +010012870 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12871 .dac_nids = alc262_dac_nids,
12872 .hp_nid = 0x03,
12873 .dig_out_nid = ALC262_DIGOUT_NID,
12874 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12875 .channel_mode = alc262_modes,
12876 .input_mux = &alc262_fujitsu_capture_source,
12877 .unsol_event = alc262_lenovo_3000_unsol_event,
12878 },
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012879 [ALC262_NEC] = {
12880 .mixers = { alc262_nec_mixer },
12881 .init_verbs = { alc262_nec_verbs },
12882 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12883 .dac_nids = alc262_dac_nids,
12884 .hp_nid = 0x03,
12885 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12886 .channel_mode = alc262_modes,
12887 .input_mux = &alc262_capture_source,
12888 },
Kailang Yang4e555fe2008-08-26 13:05:55 +020012889 [ALC262_TOSHIBA_S06] = {
12890 .mixers = { alc262_toshiba_s06_mixer },
12891 .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
12892 alc262_eapd_verbs },
12893 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12894 .capsrc_nids = alc262_dmic_capsrc_nids,
12895 .dac_nids = alc262_dac_nids,
12896 .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
Takashi Iwaiae14ef62009-06-22 08:16:56 +020012897 .num_adc_nids = 1, /* single ADC */
Kailang Yang4e555fe2008-08-26 13:05:55 +020012898 .dig_out_nid = ALC262_DIGOUT_NID,
12899 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12900 .channel_mode = alc262_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012901 .unsol_event = alc_sku_unsol_event,
12902 .setup = alc262_toshiba_s06_setup,
12903 .init_hook = alc_inithook,
Kailang Yang4e555fe2008-08-26 13:05:55 +020012904 },
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012905 [ALC262_TOSHIBA_RX1] = {
12906 .mixers = { alc262_toshiba_rx1_mixer },
12907 .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
12908 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12909 .dac_nids = alc262_dac_nids,
12910 .hp_nid = 0x03,
12911 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12912 .channel_mode = alc262_modes,
12913 .input_mux = &alc262_capture_source,
12914 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012915 .setup = alc262_hippo_setup,
12916 .init_hook = alc262_hippo_automute,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012917 },
Tony Vroonba340e82009-02-02 19:01:30 +000012918 [ALC262_TYAN] = {
12919 .mixers = { alc262_tyan_mixer },
12920 .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
12921 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12922 .dac_nids = alc262_dac_nids,
12923 .hp_nid = 0x02,
12924 .dig_out_nid = ALC262_DIGOUT_NID,
12925 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12926 .channel_mode = alc262_modes,
12927 .input_mux = &alc262_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012928 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012929 .setup = alc262_tyan_setup,
12930 .init_hook = alc_automute_amp,
Tony Vroonba340e82009-02-02 19:01:30 +000012931 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012932};
12933
12934static int patch_alc262(struct hda_codec *codec)
12935{
12936 struct alc_spec *spec;
12937 int board_config;
12938 int err;
12939
Robert P. J. Daydc041e02006-12-19 14:44:15 +010012940 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010012941 if (spec == NULL)
12942 return -ENOMEM;
12943
12944 codec->spec = spec;
12945#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012946 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
12947 * under-run
12948 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012949 {
12950 int tmp;
12951 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
12952 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
12953 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
12954 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
12955 }
12956#endif
Kailang Yangda00c242010-03-19 11:23:45 +010012957 alc_auto_parse_customize_define(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012958
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020012959 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
12960
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012961 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
12962 alc262_models,
12963 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +010012964
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012965 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020012966 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
12967 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010012968 board_config = ALC262_AUTO;
12969 }
12970
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010012971 if (board_config == ALC262_AUTO) {
12972 alc_pick_fixup(codec, NULL, alc262_fixup_tbl, alc262_fixups);
12973 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
12974 }
Takashi Iwai18675e42010-09-08 15:55:44 +020012975
Kailang Yangdf694da2005-12-05 19:42:22 +010012976 if (board_config == ALC262_AUTO) {
12977 /* automatic parse from the BIOS config */
12978 err = alc262_parse_auto_config(codec);
12979 if (err < 0) {
12980 alc_free(codec);
12981 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012982 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012983 printk(KERN_INFO
12984 "hda_codec: Cannot set up configuration "
12985 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010012986 board_config = ALC262_BASIC;
12987 }
12988 }
12989
Takashi Iwaidc1eae22010-07-29 15:30:02 +020012990 if (!spec->no_analog && has_cdefine_beep(codec)) {
Takashi Iwai07eba612009-02-19 08:06:35 +010012991 err = snd_hda_attach_beep_device(codec, 0x1);
12992 if (err < 0) {
12993 alc_free(codec);
12994 return err;
12995 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090012996 }
12997
Kailang Yangdf694da2005-12-05 19:42:22 +010012998 if (board_config != ALC262_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020012999 setup_preset(codec, &alc262_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010013000
Kailang Yangdf694da2005-12-05 19:42:22 +010013001 spec->stream_analog_playback = &alc262_pcm_analog_playback;
13002 spec->stream_analog_capture = &alc262_pcm_analog_capture;
Kailang Yangea1fb292008-08-26 12:58:38 +020013003
Kailang Yangdf694da2005-12-05 19:42:22 +010013004 spec->stream_digital_playback = &alc262_pcm_digital_playback;
13005 spec->stream_digital_capture = &alc262_pcm_digital_capture;
13006
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013007 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwai8c927b42009-06-22 10:56:54 +020013008 int i;
13009 /* check whether the digital-mic has to be supported */
13010 for (i = 0; i < spec->input_mux->num_items; i++) {
13011 if (spec->input_mux->items[i].index >= 9)
13012 break;
13013 }
13014 if (i < spec->input_mux->num_items) {
13015 /* use only ADC0 */
13016 spec->adc_nids = alc262_dmic_adc_nids;
13017 spec->num_adc_nids = 1;
13018 spec->capsrc_nids = alc262_dmic_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +010013019 } else {
Takashi Iwai8c927b42009-06-22 10:56:54 +020013020 /* all analog inputs */
13021 /* check whether NID 0x07 is valid */
13022 unsigned int wcap = get_wcaps(codec, 0x07);
13023
13024 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020013025 wcap = get_wcaps_type(wcap);
Takashi Iwai8c927b42009-06-22 10:56:54 +020013026 if (wcap != AC_WID_AUD_IN) {
13027 spec->adc_nids = alc262_adc_nids_alt;
13028 spec->num_adc_nids =
13029 ARRAY_SIZE(alc262_adc_nids_alt);
13030 spec->capsrc_nids = alc262_capsrc_nids_alt;
13031 } else {
13032 spec->adc_nids = alc262_adc_nids;
13033 spec->num_adc_nids =
13034 ARRAY_SIZE(alc262_adc_nids);
13035 spec->capsrc_nids = alc262_capsrc_nids;
13036 }
Kailang Yangdf694da2005-12-05 19:42:22 +010013037 }
13038 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +010013039 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020013040 set_capture_mixer(codec);
Takashi Iwaidc1eae22010-07-29 15:30:02 +020013041 if (!spec->no_analog && has_cdefine_beep(codec))
Takashi Iwai07eba612009-02-19 08:06:35 +010013042 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Kailang Yangdf694da2005-12-05 19:42:22 +010013043
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010013044 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwai18675e42010-09-08 15:55:44 +020013045
Takashi Iwai2134ea42008-01-10 16:53:55 +010013046 spec->vmaster_nid = 0x0c;
13047
Kailang Yangdf694da2005-12-05 19:42:22 +010013048 codec->patch_ops = alc_patch_ops;
13049 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010013050 spec->init_hook = alc262_auto_init;
Kailang Yangbf1b0222010-10-21 08:49:56 +020013051
13052 alc_init_jacks(codec);
Takashi Iwaicb53c622007-08-10 17:21:45 +020013053#ifdef CONFIG_SND_HDA_POWER_SAVE
13054 if (!spec->loopback.amplist)
13055 spec->loopback.amplist = alc262_loopbacks;
13056#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020013057
Kailang Yangdf694da2005-12-05 19:42:22 +010013058 return 0;
13059}
13060
Kailang Yangdf694da2005-12-05 19:42:22 +010013061/*
Kailang Yanga361d842007-06-05 12:30:55 +020013062 * ALC268 channel source setting (2 channel)
13063 */
13064#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
13065#define alc268_modes alc260_modes
Kailang Yangea1fb292008-08-26 12:58:38 +020013066
Kailang Yanga361d842007-06-05 12:30:55 +020013067static hda_nid_t alc268_dac_nids[2] = {
13068 /* front, hp */
13069 0x02, 0x03
13070};
13071
13072static hda_nid_t alc268_adc_nids[2] = {
13073 /* ADC0-1 */
13074 0x08, 0x07
13075};
13076
13077static hda_nid_t alc268_adc_nids_alt[1] = {
13078 /* ADC0 */
13079 0x08
13080};
13081
Takashi Iwaie1406342008-02-11 18:32:32 +010013082static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
13083
Kailang Yanga361d842007-06-05 12:30:55 +020013084static struct snd_kcontrol_new alc268_base_mixer[] = {
13085 /* output mixer control */
13086 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
13087 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13088 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
13089 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013090 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13091 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
13092 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +020013093 { }
13094};
13095
Takashi Iwai42171c12009-05-08 14:11:43 +020013096static struct snd_kcontrol_new alc268_toshiba_mixer[] = {
13097 /* output mixer control */
13098 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
13099 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
13100 ALC262_HIPPO_MASTER_SWITCH,
David Henningsson5f99f862011-01-04 15:24:24 +010013101 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13102 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
13103 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020013104 { }
13105};
13106
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013107/* bind Beep switches of both NID 0x0f and 0x10 */
13108static struct hda_bind_ctls alc268_bind_beep_sw = {
13109 .ops = &snd_hda_bind_sw,
13110 .values = {
13111 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
13112 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
13113 0
13114 },
13115};
13116
13117static struct snd_kcontrol_new alc268_beep_mixer[] = {
13118 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
13119 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
13120 { }
13121};
13122
Kailang Yangd1a991a2007-08-15 16:21:59 +020013123static struct hda_verb alc268_eapd_verbs[] = {
13124 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
13125 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
13126 { }
13127};
13128
Takashi Iwaid2738092007-08-16 14:59:45 +020013129/* Toshiba specific */
Takashi Iwaid2738092007-08-16 14:59:45 +020013130static struct hda_verb alc268_toshiba_verbs[] = {
13131 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13132 { } /* end */
13133};
13134
13135/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +020013136/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +020013137static struct hda_bind_ctls alc268_acer_bind_master_vol = {
13138 .ops = &snd_hda_bind_vol,
13139 .values = {
13140 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
13141 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
13142 0
13143 },
13144};
13145
Takashi Iwai889c4392007-08-23 18:56:52 +020013146/* mute/unmute internal speaker according to the hp jack and mute state */
13147static void alc268_acer_automute(struct hda_codec *codec, int force)
13148{
13149 struct alc_spec *spec = codec->spec;
13150 unsigned int mute;
13151
13152 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080013153 spec->jack_present = snd_hda_jack_detect(codec, 0x14);
Takashi Iwai889c4392007-08-23 18:56:52 +020013154 spec->sense_updated = 1;
13155 }
13156 if (spec->jack_present)
13157 mute = HDA_AMP_MUTE; /* mute internal speaker */
13158 else /* unmute internal speaker if necessary */
13159 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
13160 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
13161 HDA_AMP_MUTE, mute);
13162}
13163
13164
13165/* bind hp and internal speaker mute (with plug check) */
13166static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
13167 struct snd_ctl_elem_value *ucontrol)
13168{
13169 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
13170 long *valp = ucontrol->value.integer.value;
13171 int change;
13172
Takashi Iwai8de56b72009-07-24 16:51:47 +020013173 change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
Takashi Iwai889c4392007-08-23 18:56:52 +020013174 if (change)
13175 alc268_acer_automute(codec, 0);
13176 return change;
13177}
Takashi Iwaid2738092007-08-16 14:59:45 +020013178
Kailang Yang8ef355d2008-08-26 13:10:22 +020013179static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
13180 /* output mixer control */
13181 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13182 {
13183 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13184 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013185 .subdevice = HDA_SUBDEV_AMP_FLAG,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013186 .info = snd_hda_mixer_amp_switch_info,
13187 .get = snd_hda_mixer_amp_switch_get,
13188 .put = alc268_acer_master_sw_put,
13189 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13190 },
13191 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
13192 { }
13193};
13194
Takashi Iwaid2738092007-08-16 14:59:45 +020013195static struct snd_kcontrol_new alc268_acer_mixer[] = {
13196 /* output mixer control */
13197 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13198 {
13199 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13200 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013201 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwaid2738092007-08-16 14:59:45 +020013202 .info = snd_hda_mixer_amp_switch_info,
13203 .get = snd_hda_mixer_amp_switch_get,
13204 .put = alc268_acer_master_sw_put,
13205 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13206 },
David Henningsson5f99f862011-01-04 15:24:24 +010013207 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13208 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
13209 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +020013210 { }
13211};
13212
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013213static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
13214 /* output mixer control */
13215 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13216 {
13217 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13218 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013219 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013220 .info = snd_hda_mixer_amp_switch_info,
13221 .get = snd_hda_mixer_amp_switch_get,
13222 .put = alc268_acer_master_sw_put,
13223 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13224 },
David Henningsson5f99f862011-01-04 15:24:24 +010013225 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13226 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013227 { }
13228};
13229
Kailang Yang8ef355d2008-08-26 13:10:22 +020013230static struct hda_verb alc268_acer_aspire_one_verbs[] = {
13231 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13232 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13233 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13234 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13235 {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
13236 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
13237 { }
13238};
13239
Takashi Iwaid2738092007-08-16 14:59:45 +020013240static struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013241 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
13242 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +020013243 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13244 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013245 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13246 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +020013247 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13248 { }
13249};
13250
13251/* unsolicited event for HP jack sensing */
Takashi Iwai42171c12009-05-08 14:11:43 +020013252#define alc268_toshiba_unsol_event alc262_hippo_unsol_event
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013253#define alc268_toshiba_setup alc262_hippo_setup
13254#define alc268_toshiba_automute alc262_hippo_automute
Takashi Iwaid2738092007-08-16 14:59:45 +020013255
13256static void alc268_acer_unsol_event(struct hda_codec *codec,
13257 unsigned int res)
13258{
Takashi Iwai889c4392007-08-23 18:56:52 +020013259 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020013260 return;
13261 alc268_acer_automute(codec, 1);
13262}
13263
Takashi Iwai889c4392007-08-23 18:56:52 +020013264static void alc268_acer_init_hook(struct hda_codec *codec)
13265{
13266 alc268_acer_automute(codec, 1);
13267}
13268
Kailang Yang8ef355d2008-08-26 13:10:22 +020013269/* toggle speaker-output according to the hp-jack state */
13270static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
13271{
13272 unsigned int present;
13273 unsigned char bits;
13274
Wu Fengguang864f92b2009-11-18 12:38:02 +080013275 present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013276 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang8ef355d2008-08-26 13:10:22 +020013277 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013278 HDA_AMP_MUTE, bits);
Kailang Yang8ef355d2008-08-26 13:10:22 +020013279 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013280 HDA_AMP_MUTE, bits);
Kailang Yang8ef355d2008-08-26 13:10:22 +020013281}
13282
Kailang Yang8ef355d2008-08-26 13:10:22 +020013283static void alc268_acer_lc_unsol_event(struct hda_codec *codec,
13284 unsigned int res)
13285{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013286 switch (res >> 26) {
13287 case ALC880_HP_EVENT:
Kailang Yang8ef355d2008-08-26 13:10:22 +020013288 alc268_aspire_one_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013289 break;
13290 case ALC880_MIC_EVENT:
13291 alc_mic_automute(codec);
13292 break;
13293 }
13294}
13295
13296static void alc268_acer_lc_setup(struct hda_codec *codec)
13297{
13298 struct alc_spec *spec = codec->spec;
13299 spec->ext_mic.pin = 0x18;
13300 spec->ext_mic.mux_idx = 0;
13301 spec->int_mic.pin = 0x12;
13302 spec->int_mic.mux_idx = 6;
13303 spec->auto_mic = 1;
Kailang Yang8ef355d2008-08-26 13:10:22 +020013304}
13305
13306static void alc268_acer_lc_init_hook(struct hda_codec *codec)
13307{
13308 alc268_aspire_one_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013309 alc_mic_automute(codec);
Kailang Yang8ef355d2008-08-26 13:10:22 +020013310}
13311
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013312static struct snd_kcontrol_new alc268_dell_mixer[] = {
13313 /* output mixer control */
13314 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13315 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13316 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13317 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013318 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13319 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013320 { }
13321};
13322
13323static struct hda_verb alc268_dell_verbs[] = {
13324 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13325 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13326 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013327 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013328 { }
13329};
13330
13331/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013332static void alc268_dell_setup(struct hda_codec *codec)
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013333{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013334 struct alc_spec *spec = codec->spec;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013335
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013336 spec->autocfg.hp_pins[0] = 0x15;
13337 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013338 spec->ext_mic.pin = 0x18;
13339 spec->ext_mic.mux_idx = 0;
13340 spec->int_mic.pin = 0x19;
13341 spec->int_mic.mux_idx = 1;
13342 spec->auto_mic = 1;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013343}
13344
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013345static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
13346 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
13347 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13348 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
13349 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
13350 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13351 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013352 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13353 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013354 { }
13355};
13356
13357static struct hda_verb alc267_quanta_il1_verbs[] = {
13358 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13359 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
13360 { }
13361};
13362
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013363static void alc267_quanta_il1_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013364{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013365 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013366 spec->autocfg.hp_pins[0] = 0x15;
13367 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013368 spec->ext_mic.pin = 0x18;
13369 spec->ext_mic.mux_idx = 0;
13370 spec->int_mic.pin = 0x19;
13371 spec->int_mic.mux_idx = 1;
13372 spec->auto_mic = 1;
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013373}
13374
Kailang Yanga361d842007-06-05 12:30:55 +020013375/*
13376 * generic initialization of ADC, input mixers and output mixers
13377 */
13378static struct hda_verb alc268_base_init_verbs[] = {
13379 /* Unmute DAC0-1 and set vol = 0 */
13380 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020013381 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020013382
13383 /*
13384 * Set up output mixers (0x0c - 0x0e)
13385 */
13386 /* set vol=0 to output mixers */
13387 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020013388 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
13389
13390 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13391 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13392
13393 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
13394 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
13395 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
13396 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13397 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13398 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13399 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13400 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13401
13402 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13403 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13404 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13405 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013406 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013407
13408 /* set PCBEEP vol = 0, mute connections */
13409 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13410 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13411 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020013412
Jiang Zhea9b3aa82007-12-20 13:13:13 +010013413 /* Unmute Selector 23h,24h and set the default input to mic-in */
Kailang Yangea1fb292008-08-26 12:58:38 +020013414
Jiang Zhea9b3aa82007-12-20 13:13:13 +010013415 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
13416 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13417 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
13418 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013419
Kailang Yanga361d842007-06-05 12:30:55 +020013420 { }
13421};
13422
13423/*
13424 * generic initialization of ADC, input mixers and output mixers
13425 */
13426static struct hda_verb alc268_volume_init_verbs[] = {
13427 /* set output DAC */
Takashi Iwai4cfb91c2009-01-23 12:53:09 +010013428 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13429 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020013430
13431 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13432 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13433 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13434 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13435 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13436
Kailang Yanga361d842007-06-05 12:30:55 +020013437 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020013438 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13439 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13440
13441 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013442 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013443
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013444 /* set PCBEEP vol = 0, mute connections */
13445 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13446 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13447 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020013448
13449 { }
13450};
13451
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013452static struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = {
13453 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13454 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
13455 { } /* end */
13456};
13457
Kailang Yanga361d842007-06-05 12:30:55 +020013458static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
13459 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13460 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013461 _DEFINE_CAPSRC(1),
Kailang Yanga361d842007-06-05 12:30:55 +020013462 { } /* end */
13463};
13464
13465static struct snd_kcontrol_new alc268_capture_mixer[] = {
13466 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13467 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
13468 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
13469 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013470 _DEFINE_CAPSRC(2),
Kailang Yanga361d842007-06-05 12:30:55 +020013471 { } /* end */
13472};
13473
13474static struct hda_input_mux alc268_capture_source = {
13475 .num_items = 4,
13476 .items = {
13477 { "Mic", 0x0 },
13478 { "Front Mic", 0x1 },
13479 { "Line", 0x2 },
13480 { "CD", 0x3 },
13481 },
13482};
13483
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013484static struct hda_input_mux alc268_acer_capture_source = {
13485 .num_items = 3,
13486 .items = {
13487 { "Mic", 0x0 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013488 { "Internal Mic", 0x1 },
13489 { "Line", 0x2 },
13490 },
13491};
13492
13493static struct hda_input_mux alc268_acer_dmic_capture_source = {
13494 .num_items = 3,
13495 .items = {
13496 { "Mic", 0x0 },
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013497 { "Internal Mic", 0x6 },
13498 { "Line", 0x2 },
13499 },
13500};
13501
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013502#ifdef CONFIG_SND_DEBUG
13503static struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013504 /* Volume widgets */
13505 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13506 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13507 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
13508 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
13509 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
13510 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
13511 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
13512 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
13513 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
13514 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
13515 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
13516 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
13517 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010013518 /* The below appears problematic on some hardwares */
13519 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013520 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13521 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
13522 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
13523 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
13524
13525 /* Modes for retasking pin widgets */
13526 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
13527 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
13528 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
13529 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
13530
13531 /* Controls for GPIO pins, assuming they are configured as outputs */
13532 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
13533 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
13534 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
13535 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
13536
13537 /* Switches to allow the digital SPDIF output pin to be enabled.
13538 * The ALC268 does not have an SPDIF input.
13539 */
13540 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
13541
13542 /* A switch allowing EAPD to be enabled. Some laptops seem to use
13543 * this output to turn on an external amplifier.
13544 */
13545 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
13546 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
13547
13548 { } /* end */
13549};
13550#endif
13551
Kailang Yanga361d842007-06-05 12:30:55 +020013552/* create input playback/capture controls for the given pin */
13553static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
13554 const char *ctlname, int idx)
13555{
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013556 hda_nid_t dac;
Kailang Yanga361d842007-06-05 12:30:55 +020013557 int err;
13558
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013559 switch (nid) {
13560 case 0x14:
13561 case 0x16:
13562 dac = 0x02;
13563 break;
13564 case 0x15:
Takashi Iwaib08b1632010-07-30 14:08:25 +020013565 case 0x1a: /* ALC259/269 only */
13566 case 0x1b: /* ALC259/269 only */
Kailang Yang531d8792010-04-09 10:57:33 +020013567 case 0x21: /* ALC269vb has this pin, too */
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013568 dac = 0x03;
13569 break;
13570 default:
Takashi Iwaic7a94342010-07-30 14:10:43 +020013571 snd_printd(KERN_WARNING "hda_codec: "
13572 "ignoring pin 0x%x as unknown\n", nid);
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013573 return 0;
13574 }
13575 if (spec->multiout.dac_nids[0] != dac &&
13576 spec->multiout.dac_nids[1] != dac) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013577 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013578 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
Kailang Yanga361d842007-06-05 12:30:55 +020013579 HDA_OUTPUT));
13580 if (err < 0)
13581 return err;
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013582 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
13583 }
13584
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013585 if (nid != 0x16)
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013586 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Kailang Yanga361d842007-06-05 12:30:55 +020013587 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013588 else /* mono */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013589 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013590 HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013591 if (err < 0)
13592 return err;
13593 return 0;
13594}
13595
13596/* add playback controls from the parsed DAC table */
13597static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
13598 const struct auto_pin_cfg *cfg)
13599{
13600 hda_nid_t nid;
13601 int err;
13602
Kailang Yanga361d842007-06-05 12:30:55 +020013603 spec->multiout.dac_nids = spec->private_dac_nids;
Kailang Yanga361d842007-06-05 12:30:55 +020013604
13605 nid = cfg->line_out_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013606 if (nid) {
13607 const char *name;
13608 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
13609 name = "Speaker";
13610 else
13611 name = "Front";
13612 err = alc268_new_analog_output(spec, nid, name, 0);
13613 if (err < 0)
13614 return err;
13615 }
Kailang Yanga361d842007-06-05 12:30:55 +020013616
13617 nid = cfg->speaker_pins[0];
13618 if (nid == 0x1d) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013619 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Speaker",
Kailang Yanga361d842007-06-05 12:30:55 +020013620 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
13621 if (err < 0)
13622 return err;
David Henningsson7bfb9c02010-08-02 13:13:25 +020013623 } else if (nid) {
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013624 err = alc268_new_analog_output(spec, nid, "Speaker", 0);
13625 if (err < 0)
13626 return err;
Kailang Yanga361d842007-06-05 12:30:55 +020013627 }
13628 nid = cfg->hp_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013629 if (nid) {
13630 err = alc268_new_analog_output(spec, nid, "Headphone", 0);
13631 if (err < 0)
13632 return err;
13633 }
Kailang Yanga361d842007-06-05 12:30:55 +020013634
13635 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
13636 if (nid == 0x16) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013637 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, "Mono",
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013638 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013639 if (err < 0)
13640 return err;
13641 }
Kailang Yangea1fb292008-08-26 12:58:38 +020013642 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020013643}
13644
13645/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020013646static int alc268_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yanga361d842007-06-05 12:30:55 +020013647 const struct auto_pin_cfg *cfg)
13648{
Takashi Iwai05f5f472009-08-25 13:10:18 +020013649 return alc_auto_create_input_ctls(codec, cfg, 0, 0x23, 0x24);
Kailang Yanga361d842007-06-05 12:30:55 +020013650}
13651
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013652static void alc268_auto_set_output_and_unmute(struct hda_codec *codec,
13653 hda_nid_t nid, int pin_type)
13654{
13655 int idx;
13656
13657 alc_set_pin_output(codec, nid, pin_type);
13658 if (nid == 0x14 || nid == 0x16)
13659 idx = 0;
13660 else
13661 idx = 1;
13662 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
13663}
13664
13665static void alc268_auto_init_multi_out(struct hda_codec *codec)
13666{
13667 struct alc_spec *spec = codec->spec;
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013668 int i;
13669
13670 for (i = 0; i < spec->autocfg.line_outs; i++) {
13671 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013672 int pin_type = get_pin_type(spec->autocfg.line_out_type);
13673 alc268_auto_set_output_and_unmute(codec, nid, pin_type);
13674 }
13675}
13676
13677static void alc268_auto_init_hp_out(struct hda_codec *codec)
13678{
13679 struct alc_spec *spec = codec->spec;
13680 hda_nid_t pin;
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013681 int i;
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013682
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013683 for (i = 0; i < spec->autocfg.hp_outs; i++) {
13684 pin = spec->autocfg.hp_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013685 alc268_auto_set_output_and_unmute(codec, pin, PIN_HP);
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013686 }
13687 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
13688 pin = spec->autocfg.speaker_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013689 alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT);
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013690 }
13691 if (spec->autocfg.mono_out_pin)
13692 snd_hda_codec_write(codec, spec->autocfg.mono_out_pin, 0,
13693 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013694}
13695
Kailang Yanga361d842007-06-05 12:30:55 +020013696static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
13697{
13698 struct alc_spec *spec = codec->spec;
13699 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
13700 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
13701 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
13702 unsigned int dac_vol1, dac_vol2;
13703
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013704 if (line_nid == 0x1d || speaker_nid == 0x1d) {
Kailang Yanga361d842007-06-05 12:30:55 +020013705 snd_hda_codec_write(codec, speaker_nid, 0,
13706 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013707 /* mute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013708 snd_hda_codec_write(codec, 0x0f, 0,
13709 AC_VERB_SET_AMP_GAIN_MUTE,
13710 AMP_IN_UNMUTE(1));
13711 snd_hda_codec_write(codec, 0x10, 0,
13712 AC_VERB_SET_AMP_GAIN_MUTE,
13713 AMP_IN_UNMUTE(1));
13714 } else {
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013715 /* unmute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013716 snd_hda_codec_write(codec, 0x0f, 0,
13717 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13718 snd_hda_codec_write(codec, 0x10, 0,
13719 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13720 }
13721
13722 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020013723 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013724 dac_vol2 = AMP_OUT_ZERO;
13725 else if (line_nid == 0x15)
13726 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020013727 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013728 dac_vol2 = AMP_OUT_ZERO;
13729 else if (hp_nid == 0x15)
13730 dac_vol1 = AMP_OUT_ZERO;
13731 if (line_nid != 0x16 || hp_nid != 0x16 ||
13732 spec->autocfg.line_out_pins[1] != 0x16 ||
13733 spec->autocfg.line_out_pins[2] != 0x16)
13734 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
13735
13736 snd_hda_codec_write(codec, 0x02, 0,
13737 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
13738 snd_hda_codec_write(codec, 0x03, 0,
13739 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
13740}
13741
Sasha Alexandrdef319f2009-06-16 16:00:15 -040013742/* pcm configuration: identical with ALC880 */
Kailang Yanga361d842007-06-05 12:30:55 +020013743#define alc268_pcm_analog_playback alc880_pcm_analog_playback
13744#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010013745#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020013746#define alc268_pcm_digital_playback alc880_pcm_digital_playback
13747
13748/*
13749 * BIOS auto configuration
13750 */
13751static int alc268_parse_auto_config(struct hda_codec *codec)
13752{
13753 struct alc_spec *spec = codec->spec;
13754 int err;
13755 static hda_nid_t alc268_ignore[] = { 0 };
13756
13757 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13758 alc268_ignore);
13759 if (err < 0)
13760 return err;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013761 if (!spec->autocfg.line_outs) {
13762 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
13763 spec->multiout.max_channels = 2;
13764 spec->no_analog = 1;
13765 goto dig_only;
13766 }
Kailang Yanga361d842007-06-05 12:30:55 +020013767 return 0; /* can't find valid BIOS pin config */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013768 }
Kailang Yanga361d842007-06-05 12:30:55 +020013769 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
13770 if (err < 0)
13771 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020013772 err = alc268_auto_create_input_ctls(codec, &spec->autocfg);
Kailang Yanga361d842007-06-05 12:30:55 +020013773 if (err < 0)
13774 return err;
13775
13776 spec->multiout.max_channels = 2;
13777
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013778 dig_only:
Kailang Yanga361d842007-06-05 12:30:55 +020013779 /* digital only support output */
Takashi Iwai757899a2010-07-30 10:48:14 +020013780 alc_auto_parse_digital(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +020013781 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013782 add_mixer(spec, spec->kctls.list);
Kailang Yanga361d842007-06-05 12:30:55 +020013783
Takashi Iwai892981f2009-03-02 08:04:35 +010013784 if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013785 add_mixer(spec, alc268_beep_mixer);
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013786
Takashi Iwaid88897e2008-10-31 15:01:37 +010013787 add_verb(spec, alc268_volume_init_verbs);
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030013788 spec->num_mux_defs = 2;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020013789 spec->input_mux = &spec->private_imux[0];
Kailang Yanga361d842007-06-05 12:30:55 +020013790
Takashi Iwai776e1842007-08-29 15:07:11 +020013791 err = alc_auto_add_mic_boost(codec);
13792 if (err < 0)
13793 return err;
13794
Kailang Yang6227cdc2010-02-25 08:36:52 +010013795 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai1d955eb2009-06-29 11:33:53 +020013796
Kailang Yanga361d842007-06-05 12:30:55 +020013797 return 1;
13798}
13799
Kailang Yanga361d842007-06-05 12:30:55 +020013800#define alc268_auto_init_analog_input alc882_auto_init_analog_input
13801
13802/* init callback for auto-configuration model -- overriding the default init */
13803static void alc268_auto_init(struct hda_codec *codec)
13804{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013805 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020013806 alc268_auto_init_multi_out(codec);
13807 alc268_auto_init_hp_out(codec);
13808 alc268_auto_init_mono_speaker_out(codec);
13809 alc268_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020013810 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013811 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020013812 alc_inithook(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020013813}
13814
13815/*
13816 * configuration and preset
13817 */
Takashi Iwaiea734962011-01-17 11:29:34 +010013818static const char * const alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013819 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020013820 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020013821 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020013822 [ALC268_ACER] = "acer",
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013823 [ALC268_ACER_DMIC] = "acer-dmic",
Kailang Yang8ef355d2008-08-26 13:10:22 +020013824 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013825 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013826 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013827#ifdef CONFIG_SND_DEBUG
13828 [ALC268_TEST] = "test",
13829#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013830 [ALC268_AUTO] = "auto",
13831};
13832
13833static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020013834 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013835 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010013836 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013837 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010013838 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020013839 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
13840 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013841 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Daniel T Chena1bf8082009-11-01 18:32:29 -050013842 SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0,
13843 "Dell Inspiron Mini9/Vostro A90", ALC268_DELL),
Takashi Iwai33d78672009-09-08 11:03:41 +020013844 /* almost compatible with toshiba but with optional digital outs;
13845 * auto-probing seems working fine
13846 */
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013847 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series",
Takashi Iwai33d78672009-09-08 11:03:41 +020013848 ALC268_AUTO),
Kailang Yanga361d842007-06-05 12:30:55 +020013849 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013850 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Tony Vroon378bd6a2008-06-04 12:08:30 +020013851 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020013852 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013853 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Kailang Yanga361d842007-06-05 12:30:55 +020013854 {}
13855};
13856
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013857/* Toshiba laptops have no unique PCI SSID but only codec SSID */
13858static struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
13859 SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO),
13860 SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO),
13861 SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
13862 ALC268_TOSHIBA),
13863 {}
13864};
13865
Kailang Yanga361d842007-06-05 12:30:55 +020013866static struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013867 [ALC267_QUANTA_IL1] = {
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013868 .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer,
13869 alc268_capture_nosrc_mixer },
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013870 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13871 alc267_quanta_il1_verbs },
13872 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13873 .dac_nids = alc268_dac_nids,
13874 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13875 .adc_nids = alc268_adc_nids_alt,
13876 .hp_nid = 0x03,
13877 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13878 .channel_mode = alc268_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013879 .unsol_event = alc_sku_unsol_event,
13880 .setup = alc267_quanta_il1_setup,
13881 .init_hook = alc_inithook,
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013882 },
Kailang Yanga361d842007-06-05 12:30:55 +020013883 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013884 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13885 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020013886 .init_verbs = { alc268_base_init_verbs },
13887 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13888 .dac_nids = alc268_dac_nids,
13889 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13890 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013891 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020013892 .hp_nid = 0x03,
13893 .dig_out_nid = ALC268_DIGOUT_NID,
13894 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13895 .channel_mode = alc268_modes,
13896 .input_mux = &alc268_capture_source,
13897 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013898 [ALC268_TOSHIBA] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020013899 .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013900 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013901 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13902 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013903 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13904 .dac_nids = alc268_dac_nids,
13905 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13906 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013907 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013908 .hp_nid = 0x03,
13909 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13910 .channel_mode = alc268_modes,
13911 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020013912 .unsol_event = alc268_toshiba_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013913 .setup = alc268_toshiba_setup,
13914 .init_hook = alc268_toshiba_automute,
Takashi Iwaid2738092007-08-16 14:59:45 +020013915 },
13916 [ALC268_ACER] = {
Takashi Iwai432fd132009-09-30 08:13:44 +020013917 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013918 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013919 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13920 alc268_acer_verbs },
13921 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13922 .dac_nids = alc268_dac_nids,
13923 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13924 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013925 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020013926 .hp_nid = 0x02,
13927 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13928 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013929 .input_mux = &alc268_acer_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020013930 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020013931 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013932 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013933 [ALC268_ACER_DMIC] = {
13934 .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
13935 alc268_beep_mixer },
13936 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13937 alc268_acer_verbs },
13938 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13939 .dac_nids = alc268_dac_nids,
13940 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13941 .adc_nids = alc268_adc_nids_alt,
13942 .capsrc_nids = alc268_capsrc_nids,
13943 .hp_nid = 0x02,
13944 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13945 .channel_mode = alc268_modes,
13946 .input_mux = &alc268_acer_dmic_capture_source,
13947 .unsol_event = alc268_acer_unsol_event,
13948 .init_hook = alc268_acer_init_hook,
13949 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013950 [ALC268_ACER_ASPIRE_ONE] = {
13951 .mixers = { alc268_acer_aspire_one_mixer,
Takashi Iwai22971e32009-02-10 11:56:44 +010013952 alc268_beep_mixer,
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013953 alc268_capture_nosrc_mixer },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013954 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13955 alc268_acer_aspire_one_verbs },
13956 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13957 .dac_nids = alc268_dac_nids,
13958 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13959 .adc_nids = alc268_adc_nids_alt,
13960 .capsrc_nids = alc268_capsrc_nids,
13961 .hp_nid = 0x03,
13962 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13963 .channel_mode = alc268_modes,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013964 .unsol_event = alc268_acer_lc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013965 .setup = alc268_acer_lc_setup,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013966 .init_hook = alc268_acer_lc_init_hook,
13967 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013968 [ALC268_DELL] = {
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013969 .mixers = { alc268_dell_mixer, alc268_beep_mixer,
13970 alc268_capture_nosrc_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013971 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13972 alc268_dell_verbs },
13973 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13974 .dac_nids = alc268_dac_nids,
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013975 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13976 .adc_nids = alc268_adc_nids_alt,
13977 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013978 .hp_nid = 0x02,
13979 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13980 .channel_mode = alc268_modes,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013981 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013982 .setup = alc268_dell_setup,
13983 .init_hook = alc_inithook,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013984 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013985 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013986 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13987 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013988 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13989 alc268_toshiba_verbs },
13990 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13991 .dac_nids = alc268_dac_nids,
13992 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13993 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013994 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013995 .hp_nid = 0x03,
13996 .dig_out_nid = ALC268_DIGOUT_NID,
13997 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13998 .channel_mode = alc268_modes,
13999 .input_mux = &alc268_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014000 .setup = alc268_toshiba_setup,
14001 .init_hook = alc268_toshiba_automute,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010014002 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010014003#ifdef CONFIG_SND_DEBUG
14004 [ALC268_TEST] = {
14005 .mixers = { alc268_test_mixer, alc268_capture_mixer },
14006 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
14007 alc268_volume_init_verbs },
14008 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
14009 .dac_nids = alc268_dac_nids,
14010 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
14011 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010014012 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010014013 .hp_nid = 0x03,
14014 .dig_out_nid = ALC268_DIGOUT_NID,
14015 .num_channel_mode = ARRAY_SIZE(alc268_modes),
14016 .channel_mode = alc268_modes,
14017 .input_mux = &alc268_capture_source,
14018 },
14019#endif
Kailang Yanga361d842007-06-05 12:30:55 +020014020};
14021
14022static int patch_alc268(struct hda_codec *codec)
14023{
14024 struct alc_spec *spec;
14025 int board_config;
Takashi Iwai22971e32009-02-10 11:56:44 +010014026 int i, has_beep, err;
Kailang Yanga361d842007-06-05 12:30:55 +020014027
Julia Lawallef86f582009-12-19 08:18:03 +010014028 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yanga361d842007-06-05 12:30:55 +020014029 if (spec == NULL)
14030 return -ENOMEM;
14031
14032 codec->spec = spec;
14033
14034 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
14035 alc268_models,
14036 alc268_cfg_tbl);
14037
Takashi Iwai3abf2f32009-08-19 20:05:02 +020014038 if (board_config < 0 || board_config >= ALC268_MODEL_LAST)
14039 board_config = snd_hda_check_board_codec_sid_config(codec,
Takashi Iwai50ae0aa2010-03-08 12:09:59 +010014040 ALC268_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl);
Takashi Iwai3abf2f32009-08-19 20:05:02 +020014041
Kailang Yanga361d842007-06-05 12:30:55 +020014042 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020014043 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
14044 codec->chip_name);
Kailang Yanga361d842007-06-05 12:30:55 +020014045 board_config = ALC268_AUTO;
14046 }
14047
14048 if (board_config == ALC268_AUTO) {
14049 /* automatic parse from the BIOS config */
14050 err = alc268_parse_auto_config(codec);
14051 if (err < 0) {
14052 alc_free(codec);
14053 return err;
14054 } else if (!err) {
14055 printk(KERN_INFO
14056 "hda_codec: Cannot set up configuration "
14057 "from BIOS. Using base mode...\n");
14058 board_config = ALC268_3ST;
14059 }
14060 }
14061
14062 if (board_config != ALC268_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020014063 setup_preset(codec, &alc268_presets[board_config]);
Kailang Yanga361d842007-06-05 12:30:55 +020014064
Kailang Yanga361d842007-06-05 12:30:55 +020014065 spec->stream_analog_playback = &alc268_pcm_analog_playback;
14066 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010014067 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020014068
Kailang Yanga361d842007-06-05 12:30:55 +020014069 spec->stream_digital_playback = &alc268_pcm_digital_playback;
14070
Takashi Iwai22971e32009-02-10 11:56:44 +010014071 has_beep = 0;
14072 for (i = 0; i < spec->num_mixers; i++) {
14073 if (spec->mixers[i] == alc268_beep_mixer) {
14074 has_beep = 1;
14075 break;
14076 }
14077 }
14078
14079 if (has_beep) {
14080 err = snd_hda_attach_beep_device(codec, 0x1);
14081 if (err < 0) {
14082 alc_free(codec);
14083 return err;
14084 }
14085 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
14086 /* override the amp caps for beep generator */
14087 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010014088 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
14089 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
14090 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
14091 (0 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwai22971e32009-02-10 11:56:44 +010014092 }
Takashi Iwaiaef9d312008-02-19 13:16:41 +010014093
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010014094 if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010014095 /* check whether NID 0x07 is valid */
14096 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwai85860c02008-02-19 15:00:15 +010014097 int i;
Kailang Yanga361d842007-06-05 12:30:55 +020014098
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020014099 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010014100 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020014101 wcap = get_wcaps_type(wcap);
Takashi Iwaifdbc66262009-08-19 00:18:10 +020014102 if (spec->auto_mic ||
14103 wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010014104 spec->adc_nids = alc268_adc_nids_alt;
14105 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020014106 if (spec->auto_mic)
14107 fixup_automic_adc(codec);
Takashi Iwaifdbc66262009-08-19 00:18:10 +020014108 if (spec->auto_mic || spec->input_mux->num_items == 1)
14109 add_mixer(spec, alc268_capture_nosrc_mixer);
14110 else
14111 add_mixer(spec, alc268_capture_alt_mixer);
Takashi Iwai3866f0b2008-01-15 12:37:42 +010014112 } else {
14113 spec->adc_nids = alc268_adc_nids;
14114 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
Takashi Iwaid88897e2008-10-31 15:01:37 +010014115 add_mixer(spec, alc268_capture_mixer);
Kailang Yanga361d842007-06-05 12:30:55 +020014116 }
Takashi Iwai85860c02008-02-19 15:00:15 +010014117 /* set default input source */
14118 for (i = 0; i < spec->num_adc_nids; i++)
14119 snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
14120 0, AC_VERB_SET_CONNECT_SEL,
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030014121 i < spec->num_mux_defs ?
14122 spec->input_mux[i].items[0].index :
Takashi Iwai85860c02008-02-19 15:00:15 +010014123 spec->input_mux->items[0].index);
Kailang Yanga361d842007-06-05 12:30:55 +020014124 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010014125
14126 spec->vmaster_nid = 0x02;
14127
Kailang Yanga361d842007-06-05 12:30:55 +020014128 codec->patch_ops = alc_patch_ops;
14129 if (board_config == ALC268_AUTO)
14130 spec->init_hook = alc268_auto_init;
Kailang Yangea1fb292008-08-26 12:58:38 +020014131
Kailang Yangbf1b0222010-10-21 08:49:56 +020014132 alc_init_jacks(codec);
14133
Kailang Yanga361d842007-06-05 12:30:55 +020014134 return 0;
14135}
14136
14137/*
Kailang Yangf6a92242007-12-13 16:52:54 +010014138 * ALC269 channel source setting (2 channel)
14139 */
14140#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
14141
14142#define alc269_dac_nids alc260_dac_nids
14143
14144static hda_nid_t alc269_adc_nids[1] = {
14145 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020014146 0x08,
14147};
14148
Takashi Iwaie01bf502008-08-21 16:25:07 +020014149static hda_nid_t alc269_capsrc_nids[1] = {
14150 0x23,
14151};
14152
Kailang Yang84898e82010-02-04 14:16:14 +010014153static hda_nid_t alc269vb_adc_nids[1] = {
14154 /* ADC1 */
14155 0x09,
14156};
14157
14158static hda_nid_t alc269vb_capsrc_nids[1] = {
14159 0x22,
14160};
14161
Takashi Iwai66946352010-03-29 17:21:45 +020014162static hda_nid_t alc269_adc_candidates[] = {
14163 0x08, 0x09, 0x07,
14164};
Takashi Iwaie01bf502008-08-21 16:25:07 +020014165
Kailang Yangf6a92242007-12-13 16:52:54 +010014166#define alc269_modes alc260_modes
14167#define alc269_capture_source alc880_lg_lw_capture_source
14168
14169static struct snd_kcontrol_new alc269_base_mixer[] = {
14170 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14171 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14172 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14173 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14174 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14175 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014176 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangf6a92242007-12-13 16:52:54 +010014177 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
14178 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014179 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangf6a92242007-12-13 16:52:54 +010014180 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
14181 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
14182 { } /* end */
14183};
14184
Kailang Yang60db6b52008-08-26 13:13:00 +020014185static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
14186 /* output mixer control */
14187 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
14188 {
14189 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14190 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010014191 .subdevice = HDA_SUBDEV_AMP_FLAG,
Kailang Yang60db6b52008-08-26 13:13:00 +020014192 .info = snd_hda_mixer_amp_switch_info,
14193 .get = snd_hda_mixer_amp_switch_get,
14194 .put = alc268_acer_master_sw_put,
14195 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14196 },
14197 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14198 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014199 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020014200 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
14201 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014202 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020014203 { }
14204};
14205
Tony Vroon64154832008-11-06 15:08:49 +000014206static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
14207 /* output mixer control */
14208 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
14209 {
14210 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14211 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010014212 .subdevice = HDA_SUBDEV_AMP_FLAG,
Tony Vroon64154832008-11-06 15:08:49 +000014213 .info = snd_hda_mixer_amp_switch_info,
14214 .get = snd_hda_mixer_amp_switch_get,
14215 .put = alc268_acer_master_sw_put,
14216 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14217 },
14218 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14219 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014220 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000014221 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
14222 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014223 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000014224 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
14225 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014226 HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x1b, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000014227 { }
14228};
14229
Kailang Yang84898e82010-02-04 14:16:14 +010014230static struct snd_kcontrol_new alc269_laptop_mixer[] = {
Takashi Iwaiaa202452009-07-03 15:00:54 +020014231 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010014232 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwaiaa202452009-07-03 15:00:54 +020014233 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010014234 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yangf53281e2008-07-18 12:36:43 +020014235 { } /* end */
14236};
14237
Kailang Yang84898e82010-02-04 14:16:14 +010014238static struct snd_kcontrol_new alc269vb_laptop_mixer[] = {
14239 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14240 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14241 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
14242 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14243 { } /* end */
14244};
14245
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014246static struct snd_kcontrol_new alc269_asus_mixer[] = {
14247 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14248 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x0, HDA_INPUT),
14249 { } /* end */
14250};
14251
Kailang Yangf6a92242007-12-13 16:52:54 +010014252/* capture mixer elements */
Kailang Yang84898e82010-02-04 14:16:14 +010014253static struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
14254 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
14255 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014256 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
14257 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang84898e82010-02-04 14:16:14 +010014258 { } /* end */
14259};
14260
14261static struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = {
Kailang Yangf53281e2008-07-18 12:36:43 +020014262 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
14263 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014264 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai26f5df22008-11-03 17:39:46 +010014265 { } /* end */
14266};
14267
Kailang Yang84898e82010-02-04 14:16:14 +010014268static struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
14269 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
14270 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014271 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
14272 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang84898e82010-02-04 14:16:14 +010014273 { } /* end */
14274};
14275
14276static struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
14277 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
14278 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014279 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang84898e82010-02-04 14:16:14 +010014280 { } /* end */
14281};
14282
Takashi Iwai26f5df22008-11-03 17:39:46 +010014283/* FSC amilo */
Kailang Yang84898e82010-02-04 14:16:14 +010014284#define alc269_fujitsu_mixer alc269_laptop_mixer
Kailang Yangf53281e2008-07-18 12:36:43 +020014285
Kailang Yang60db6b52008-08-26 13:13:00 +020014286static struct hda_verb alc269_quanta_fl1_verbs[] = {
14287 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14288 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14289 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14290 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
14291 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14292 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14293 { }
14294};
14295
Tony Vroon64154832008-11-06 15:08:49 +000014296static struct hda_verb alc269_lifebook_verbs[] = {
14297 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14298 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
14299 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14300 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14301 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
14302 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14303 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14304 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
14305 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14306 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14307 { }
14308};
14309
Kailang Yang60db6b52008-08-26 13:13:00 +020014310/* toggle speaker-output according to the hp-jack state */
14311static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
14312{
14313 unsigned int present;
14314 unsigned char bits;
14315
Wu Fengguang864f92b2009-11-18 12:38:02 +080014316 present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014317 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang60db6b52008-08-26 13:13:00 +020014318 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014319 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020014320 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014321 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020014322
14323 snd_hda_codec_write(codec, 0x20, 0,
14324 AC_VERB_SET_COEF_INDEX, 0x0c);
14325 snd_hda_codec_write(codec, 0x20, 0,
14326 AC_VERB_SET_PROC_COEF, 0x680);
14327
14328 snd_hda_codec_write(codec, 0x20, 0,
14329 AC_VERB_SET_COEF_INDEX, 0x0c);
14330 snd_hda_codec_write(codec, 0x20, 0,
14331 AC_VERB_SET_PROC_COEF, 0x480);
14332}
14333
Tony Vroon64154832008-11-06 15:08:49 +000014334/* toggle speaker-output according to the hp-jacks state */
14335static void alc269_lifebook_speaker_automute(struct hda_codec *codec)
14336{
14337 unsigned int present;
14338 unsigned char bits;
14339
14340 /* Check laptop headphone socket */
Wu Fengguang864f92b2009-11-18 12:38:02 +080014341 present = snd_hda_jack_detect(codec, 0x15);
Tony Vroon64154832008-11-06 15:08:49 +000014342
14343 /* Check port replicator headphone socket */
Wu Fengguang864f92b2009-11-18 12:38:02 +080014344 present |= snd_hda_jack_detect(codec, 0x1a);
Tony Vroon64154832008-11-06 15:08:49 +000014345
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014346 bits = present ? HDA_AMP_MUTE : 0;
Tony Vroon64154832008-11-06 15:08:49 +000014347 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014348 HDA_AMP_MUTE, bits);
Tony Vroon64154832008-11-06 15:08:49 +000014349 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014350 HDA_AMP_MUTE, bits);
Tony Vroon64154832008-11-06 15:08:49 +000014351
14352 snd_hda_codec_write(codec, 0x20, 0,
14353 AC_VERB_SET_COEF_INDEX, 0x0c);
14354 snd_hda_codec_write(codec, 0x20, 0,
14355 AC_VERB_SET_PROC_COEF, 0x680);
14356
14357 snd_hda_codec_write(codec, 0x20, 0,
14358 AC_VERB_SET_COEF_INDEX, 0x0c);
14359 snd_hda_codec_write(codec, 0x20, 0,
14360 AC_VERB_SET_PROC_COEF, 0x480);
14361}
14362
Tony Vroon64154832008-11-06 15:08:49 +000014363static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
14364{
14365 unsigned int present_laptop;
14366 unsigned int present_dock;
14367
Wu Fengguang864f92b2009-11-18 12:38:02 +080014368 present_laptop = snd_hda_jack_detect(codec, 0x18);
14369 present_dock = snd_hda_jack_detect(codec, 0x1b);
Tony Vroon64154832008-11-06 15:08:49 +000014370
14371 /* Laptop mic port overrides dock mic port, design decision */
14372 if (present_dock)
14373 snd_hda_codec_write(codec, 0x23, 0,
14374 AC_VERB_SET_CONNECT_SEL, 0x3);
14375 if (present_laptop)
14376 snd_hda_codec_write(codec, 0x23, 0,
14377 AC_VERB_SET_CONNECT_SEL, 0x0);
14378 if (!present_dock && !present_laptop)
14379 snd_hda_codec_write(codec, 0x23, 0,
14380 AC_VERB_SET_CONNECT_SEL, 0x1);
14381}
14382
Kailang Yang60db6b52008-08-26 13:13:00 +020014383static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
14384 unsigned int res)
14385{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014386 switch (res >> 26) {
14387 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020014388 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014389 break;
14390 case ALC880_MIC_EVENT:
14391 alc_mic_automute(codec);
14392 break;
14393 }
Kailang Yang60db6b52008-08-26 13:13:00 +020014394}
14395
Tony Vroon64154832008-11-06 15:08:49 +000014396static void alc269_lifebook_unsol_event(struct hda_codec *codec,
14397 unsigned int res)
14398{
14399 if ((res >> 26) == ALC880_HP_EVENT)
14400 alc269_lifebook_speaker_automute(codec);
14401 if ((res >> 26) == ALC880_MIC_EVENT)
14402 alc269_lifebook_mic_autoswitch(codec);
14403}
14404
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014405static void alc269_quanta_fl1_setup(struct hda_codec *codec)
14406{
14407 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010014408 spec->autocfg.hp_pins[0] = 0x15;
14409 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014410 spec->ext_mic.pin = 0x18;
14411 spec->ext_mic.mux_idx = 0;
14412 spec->int_mic.pin = 0x19;
14413 spec->int_mic.mux_idx = 1;
14414 spec->auto_mic = 1;
14415}
14416
Kailang Yang60db6b52008-08-26 13:13:00 +020014417static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
14418{
14419 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014420 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020014421}
14422
Tony Vroon64154832008-11-06 15:08:49 +000014423static void alc269_lifebook_init_hook(struct hda_codec *codec)
14424{
14425 alc269_lifebook_speaker_automute(codec);
14426 alc269_lifebook_mic_autoswitch(codec);
14427}
14428
Kailang Yang84898e82010-02-04 14:16:14 +010014429static struct hda_verb alc269_laptop_dmic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014430 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14431 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
14432 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14433 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14434 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14435 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14436 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14437 {}
14438};
14439
Kailang Yang84898e82010-02-04 14:16:14 +010014440static struct hda_verb alc269_laptop_amic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014441 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14442 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
14443 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14444 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
14445 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14446 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14447 {}
14448};
14449
Kailang Yang84898e82010-02-04 14:16:14 +010014450static struct hda_verb alc269vb_laptop_dmic_init_verbs[] = {
14451 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
14452 {0x22, AC_VERB_SET_CONNECT_SEL, 0x06},
14453 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14454 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14455 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14456 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14457 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14458 {}
14459};
14460
14461static struct hda_verb alc269vb_laptop_amic_init_verbs[] = {
14462 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
14463 {0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
14464 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14465 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14466 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14467 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14468 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14469 {}
14470};
14471
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014472static struct hda_verb alc271_acer_dmic_verbs[] = {
14473 {0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
14474 {0x20, AC_VERB_SET_PROC_COEF, 0x4000},
14475 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14476 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14477 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14478 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14479 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00},
14480 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14481 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14482 {0x22, AC_VERB_SET_CONNECT_SEL, 6},
14483 { }
14484};
14485
Kailang Yang60db6b52008-08-26 13:13:00 +020014486/* toggle speaker-output according to the hp-jack state */
14487static void alc269_speaker_automute(struct hda_codec *codec)
14488{
Kailang Yangebb83ee2009-12-17 12:23:00 +010014489 struct alc_spec *spec = codec->spec;
14490 unsigned int nid = spec->autocfg.hp_pins[0];
Kailang Yang60db6b52008-08-26 13:13:00 +020014491 unsigned int present;
14492 unsigned char bits;
14493
Kailang Yangebb83ee2009-12-17 12:23:00 +010014494 present = snd_hda_jack_detect(codec, nid);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014495 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang60db6b52008-08-26 13:13:00 +020014496 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014497 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020014498 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014499 HDA_AMP_MUTE, bits);
Kailang Yangbf1b0222010-10-21 08:49:56 +020014500 alc_report_jack(codec, nid);
Kailang Yang60db6b52008-08-26 13:13:00 +020014501}
14502
Kailang Yang60db6b52008-08-26 13:13:00 +020014503/* unsolicited event for HP jack sensing */
Kailang Yang84898e82010-02-04 14:16:14 +010014504static void alc269_laptop_unsol_event(struct hda_codec *codec,
Kailang Yang60db6b52008-08-26 13:13:00 +020014505 unsigned int res)
14506{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014507 switch (res >> 26) {
14508 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020014509 alc269_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014510 break;
14511 case ALC880_MIC_EVENT:
14512 alc_mic_automute(codec);
14513 break;
14514 }
Kailang Yang60db6b52008-08-26 13:13:00 +020014515}
14516
Kailang Yang226b1ec2010-04-09 11:01:20 +020014517static void alc269_laptop_amic_setup(struct hda_codec *codec)
14518{
14519 struct alc_spec *spec = codec->spec;
14520 spec->autocfg.hp_pins[0] = 0x15;
14521 spec->autocfg.speaker_pins[0] = 0x14;
14522 spec->ext_mic.pin = 0x18;
14523 spec->ext_mic.mux_idx = 0;
14524 spec->int_mic.pin = 0x19;
14525 spec->int_mic.mux_idx = 1;
14526 spec->auto_mic = 1;
14527}
14528
Kailang Yang84898e82010-02-04 14:16:14 +010014529static void alc269_laptop_dmic_setup(struct hda_codec *codec)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014530{
14531 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010014532 spec->autocfg.hp_pins[0] = 0x15;
14533 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014534 spec->ext_mic.pin = 0x18;
14535 spec->ext_mic.mux_idx = 0;
14536 spec->int_mic.pin = 0x12;
14537 spec->int_mic.mux_idx = 5;
14538 spec->auto_mic = 1;
14539}
14540
Kailang Yang226b1ec2010-04-09 11:01:20 +020014541static void alc269vb_laptop_amic_setup(struct hda_codec *codec)
Kailang Yang84898e82010-02-04 14:16:14 +010014542{
14543 struct alc_spec *spec = codec->spec;
Kailang Yang226b1ec2010-04-09 11:01:20 +020014544 spec->autocfg.hp_pins[0] = 0x21;
Takashi Iwai20645d72010-03-02 11:14:01 +010014545 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014546 spec->ext_mic.pin = 0x18;
14547 spec->ext_mic.mux_idx = 0;
14548 spec->int_mic.pin = 0x19;
14549 spec->int_mic.mux_idx = 1;
14550 spec->auto_mic = 1;
14551}
14552
Kailang Yang226b1ec2010-04-09 11:01:20 +020014553static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
14554{
14555 struct alc_spec *spec = codec->spec;
14556 spec->autocfg.hp_pins[0] = 0x21;
14557 spec->autocfg.speaker_pins[0] = 0x14;
14558 spec->ext_mic.pin = 0x18;
14559 spec->ext_mic.mux_idx = 0;
14560 spec->int_mic.pin = 0x12;
14561 spec->int_mic.mux_idx = 6;
14562 spec->auto_mic = 1;
14563}
14564
Kailang Yang84898e82010-02-04 14:16:14 +010014565static void alc269_laptop_inithook(struct hda_codec *codec)
Kailang Yang60db6b52008-08-26 13:13:00 +020014566{
14567 alc269_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014568 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020014569}
14570
Kailang Yangf6a92242007-12-13 16:52:54 +010014571/*
14572 * generic initialization of ADC, input mixers and output mixers
14573 */
14574static struct hda_verb alc269_init_verbs[] = {
14575 /*
14576 * Unmute ADC0 and set the default input to mic-in
14577 */
Kailang Yang84898e82010-02-04 14:16:14 +010014578 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010014579
14580 /*
Kailang Yang84898e82010-02-04 14:16:14 +010014581 * Set up output mixers (0x02 - 0x03)
Kailang Yangf6a92242007-12-13 16:52:54 +010014582 */
14583 /* set vol=0 to output mixers */
14584 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14585 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14586
14587 /* set up input amps for analog loopback */
14588 /* Amp Indices: DAC = 0, mixer = 1 */
14589 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14590 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14591 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14592 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14593 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14594 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14595
14596 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14597 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14598 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14599 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14600 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14601 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14602 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14603
14604 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14605 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf6a92242007-12-13 16:52:54 +010014606
Kailang Yang84898e82010-02-04 14:16:14 +010014607 /* FIXME: use Mux-type input source selection */
Kailang Yangf6a92242007-12-13 16:52:54 +010014608 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14609 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang84898e82010-02-04 14:16:14 +010014610 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangf6a92242007-12-13 16:52:54 +010014611
14612 /* set EAPD */
14613 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yang84898e82010-02-04 14:16:14 +010014614 { }
14615};
14616
14617static struct hda_verb alc269vb_init_verbs[] = {
14618 /*
14619 * Unmute ADC0 and set the default input to mic-in
14620 */
14621 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14622
14623 /*
14624 * Set up output mixers (0x02 - 0x03)
14625 */
14626 /* set vol=0 to output mixers */
14627 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14628 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14629
14630 /* set up input amps for analog loopback */
14631 /* Amp Indices: DAC = 0, mixer = 1 */
14632 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14633 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14634 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14635 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14636 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14637 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14638
14639 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14640 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14641 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14642 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14643 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14644 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14645 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14646
14647 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14648 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14649
14650 /* FIXME: use Mux-type input source selection */
14651 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14652 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
14653 {0x22, AC_VERB_SET_CONNECT_SEL, 0x00},
14654
14655 /* set EAPD */
14656 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yangf6a92242007-12-13 16:52:54 +010014657 { }
14658};
14659
Takashi Iwai9d0b71b2009-08-24 14:10:30 +020014660#define alc269_auto_create_multi_out_ctls \
14661 alc268_auto_create_multi_out_ctls
Takashi Iwai05f5f472009-08-25 13:10:18 +020014662#define alc269_auto_create_input_ctls \
14663 alc268_auto_create_input_ctls
Kailang Yangf6a92242007-12-13 16:52:54 +010014664
14665#ifdef CONFIG_SND_HDA_POWER_SAVE
14666#define alc269_loopbacks alc880_loopbacks
14667#endif
14668
Sasha Alexandrdef319f2009-06-16 16:00:15 -040014669/* pcm configuration: identical with ALC880 */
Kailang Yangf6a92242007-12-13 16:52:54 +010014670#define alc269_pcm_analog_playback alc880_pcm_analog_playback
14671#define alc269_pcm_analog_capture alc880_pcm_analog_capture
14672#define alc269_pcm_digital_playback alc880_pcm_digital_playback
14673#define alc269_pcm_digital_capture alc880_pcm_digital_capture
14674
Takashi Iwaif03d3112009-03-05 14:18:16 +010014675static struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
14676 .substreams = 1,
14677 .channels_min = 2,
14678 .channels_max = 8,
14679 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14680 /* NID is set in alc_build_pcms */
14681 .ops = {
14682 .open = alc880_playback_pcm_open,
14683 .prepare = alc880_playback_pcm_prepare,
14684 .cleanup = alc880_playback_pcm_cleanup
14685 },
14686};
14687
14688static struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
14689 .substreams = 1,
14690 .channels_min = 2,
14691 .channels_max = 2,
14692 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14693 /* NID is set in alc_build_pcms */
14694};
14695
Takashi Iwaiad358792010-03-30 18:00:59 +020014696#ifdef CONFIG_SND_HDA_POWER_SAVE
14697static int alc269_mic2_for_mute_led(struct hda_codec *codec)
14698{
14699 switch (codec->subsystem_id) {
14700 case 0x103c1586:
14701 return 1;
14702 }
14703 return 0;
14704}
14705
14706static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
14707{
14708 /* update mute-LED according to the speaker mute state */
14709 if (nid == 0x01 || nid == 0x14) {
14710 int pinval;
14711 if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) &
14712 HDA_AMP_MUTE)
14713 pinval = 0x24;
14714 else
14715 pinval = 0x20;
14716 /* mic2 vref pin is used for mute LED control */
Takashi Iwaia68d5a542010-03-30 18:03:44 +020014717 snd_hda_codec_update_cache(codec, 0x19, 0,
14718 AC_VERB_SET_PIN_WIDGET_CONTROL,
14719 pinval);
Takashi Iwaiad358792010-03-30 18:00:59 +020014720 }
14721 return alc_check_power_status(codec, nid);
14722}
14723#endif /* CONFIG_SND_HDA_POWER_SAVE */
14724
Takashi Iwai840b64c2010-07-13 22:49:01 +020014725static int alc275_setup_dual_adc(struct hda_codec *codec)
14726{
14727 struct alc_spec *spec = codec->spec;
14728
14729 if (codec->vendor_id != 0x10ec0275 || !spec->auto_mic)
14730 return 0;
14731 if ((spec->ext_mic.pin >= 0x18 && spec->int_mic.pin <= 0x13) ||
14732 (spec->ext_mic.pin <= 0x12 && spec->int_mic.pin >= 0x18)) {
14733 if (spec->ext_mic.pin <= 0x12) {
14734 spec->private_adc_nids[0] = 0x08;
14735 spec->private_adc_nids[1] = 0x11;
14736 spec->private_capsrc_nids[0] = 0x23;
14737 spec->private_capsrc_nids[1] = 0x22;
14738 } else {
14739 spec->private_adc_nids[0] = 0x11;
14740 spec->private_adc_nids[1] = 0x08;
14741 spec->private_capsrc_nids[0] = 0x22;
14742 spec->private_capsrc_nids[1] = 0x23;
14743 }
14744 spec->adc_nids = spec->private_adc_nids;
14745 spec->capsrc_nids = spec->private_capsrc_nids;
14746 spec->num_adc_nids = 2;
14747 spec->dual_adc_switch = 1;
14748 snd_printdd("realtek: enabling dual ADC switchg (%02x:%02x)\n",
14749 spec->adc_nids[0], spec->adc_nids[1]);
14750 return 1;
14751 }
14752 return 0;
14753}
14754
Takashi Iwaid433a672010-09-20 15:11:54 +020014755/* different alc269-variants */
14756enum {
14757 ALC269_TYPE_NORMAL,
Kailang Yang48c88e82010-11-23 08:56:16 +010014758 ALC269_TYPE_ALC258,
Takashi Iwaid433a672010-09-20 15:11:54 +020014759 ALC269_TYPE_ALC259,
Kailang Yang48c88e82010-11-23 08:56:16 +010014760 ALC269_TYPE_ALC269VB,
14761 ALC269_TYPE_ALC270,
Takashi Iwaid433a672010-09-20 15:11:54 +020014762 ALC269_TYPE_ALC271X,
14763};
14764
Kailang Yangf6a92242007-12-13 16:52:54 +010014765/*
14766 * BIOS auto configuration
14767 */
14768static int alc269_parse_auto_config(struct hda_codec *codec)
14769{
14770 struct alc_spec *spec = codec->spec;
Takashi Iwaicfb9fb52009-02-06 17:34:03 +010014771 int err;
Kailang Yangf6a92242007-12-13 16:52:54 +010014772 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
14773
14774 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
14775 alc269_ignore);
14776 if (err < 0)
14777 return err;
14778
14779 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
14780 if (err < 0)
14781 return err;
Takashi Iwaif3550d12010-09-20 15:09:03 +020014782 if (spec->codec_variant == ALC269_TYPE_NORMAL)
14783 err = alc269_auto_create_input_ctls(codec, &spec->autocfg);
14784 else
14785 err = alc_auto_create_input_ctls(codec, &spec->autocfg, 0,
14786 0x22, 0);
Kailang Yangf6a92242007-12-13 16:52:54 +010014787 if (err < 0)
14788 return err;
14789
14790 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
14791
Takashi Iwai757899a2010-07-30 10:48:14 +020014792 alc_auto_parse_digital(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014793
Takashi Iwai603c4012008-07-30 15:01:44 +020014794 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010014795 add_mixer(spec, spec->kctls.list);
Kailang Yangf6a92242007-12-13 16:52:54 +010014796
Takashi Iwaid433a672010-09-20 15:11:54 +020014797 if (spec->codec_variant != ALC269_TYPE_NORMAL) {
Kailang Yang84898e82010-02-04 14:16:14 +010014798 add_verb(spec, alc269vb_init_verbs);
Kailang Yang6227cdc2010-02-25 08:36:52 +010014799 alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21);
Kailang Yang84898e82010-02-04 14:16:14 +010014800 } else {
14801 add_verb(spec, alc269_init_verbs);
Kailang Yang6227cdc2010-02-25 08:36:52 +010014802 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Kailang Yang84898e82010-02-04 14:16:14 +010014803 }
14804
Kailang Yangf6a92242007-12-13 16:52:54 +010014805 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020014806 spec->input_mux = &spec->private_imux[0];
Takashi Iwai840b64c2010-07-13 22:49:01 +020014807
14808 if (!alc275_setup_dual_adc(codec))
14809 fillup_priv_adc_nids(codec, alc269_adc_candidates,
14810 sizeof(alc269_adc_candidates));
Takashi Iwai66946352010-03-29 17:21:45 +020014811
Takashi Iwaie01bf502008-08-21 16:25:07 +020014812 /* set default input source */
Takashi Iwai840b64c2010-07-13 22:49:01 +020014813 if (!spec->dual_adc_switch)
Takashi Iwai748cce42010-08-04 07:37:39 +020014814 select_or_unmute_capsrc(codec, spec->capsrc_nids[0],
14815 spec->input_mux->items[0].index);
Kailang Yangf6a92242007-12-13 16:52:54 +010014816
14817 err = alc_auto_add_mic_boost(codec);
14818 if (err < 0)
14819 return err;
14820
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010014821 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020014822 set_capture_mixer(codec);
Kailang Yangf53281e2008-07-18 12:36:43 +020014823
Kailang Yangf6a92242007-12-13 16:52:54 +010014824 return 1;
14825}
14826
Takashi Iwaie9af4f32009-08-29 23:23:08 +020014827#define alc269_auto_init_multi_out alc268_auto_init_multi_out
14828#define alc269_auto_init_hp_out alc268_auto_init_hp_out
Kailang Yangf6a92242007-12-13 16:52:54 +010014829#define alc269_auto_init_analog_input alc882_auto_init_analog_input
14830
14831
14832/* init callback for auto-configuration model -- overriding the default init */
14833static void alc269_auto_init(struct hda_codec *codec)
14834{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014835 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010014836 alc269_auto_init_multi_out(codec);
14837 alc269_auto_init_hp_out(codec);
14838 alc269_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020014839 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014840 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020014841 alc_inithook(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014842}
14843
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014844#ifdef SND_HDA_NEEDS_RESUME
14845static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
14846{
14847 int val = alc_read_coef_idx(codec, 0x04);
14848 if (power_up)
14849 val |= 1 << 11;
14850 else
14851 val &= ~(1 << 11);
14852 alc_write_coef_idx(codec, 0x04, val);
14853}
14854
Kailang Yang977ddd62010-09-15 10:02:29 +020014855#ifdef CONFIG_SND_HDA_POWER_SAVE
14856static int alc269_suspend(struct hda_codec *codec, pm_message_t state)
14857{
14858 struct alc_spec *spec = codec->spec;
Kailang Yang977ddd62010-09-15 10:02:29 +020014859
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014860 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017)
14861 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014862 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014863 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014864 msleep(150);
14865 }
14866
14867 alc_shutup(codec);
14868 if (spec && spec->power_hook)
14869 spec->power_hook(codec);
14870 return 0;
14871}
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014872#endif /* CONFIG_SND_HDA_POWER_SAVE */
14873
Kailang Yang977ddd62010-09-15 10:02:29 +020014874static int alc269_resume(struct hda_codec *codec)
14875{
Kailang Yang977ddd62010-09-15 10:02:29 +020014876 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014877 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014878 msleep(150);
14879 }
14880
14881 codec->patch_ops.init(codec);
14882
14883 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014884 alc269_toggle_power_output(codec, 1);
Kailang Yang977ddd62010-09-15 10:02:29 +020014885 msleep(200);
14886 }
14887
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014888 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018)
14889 alc269_toggle_power_output(codec, 1);
Kailang Yang977ddd62010-09-15 10:02:29 +020014890
14891 snd_hda_codec_resume_amp(codec);
14892 snd_hda_codec_resume_cache(codec);
Takashi Iwai9e5341b2010-09-21 09:57:06 +020014893 hda_call_check_power_status(codec, 0x01);
Kailang Yang977ddd62010-09-15 10:02:29 +020014894 return 0;
14895}
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014896#endif /* SND_HDA_NEEDS_RESUME */
Kailang Yang977ddd62010-09-15 10:02:29 +020014897
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014898static void alc269_fixup_hweq(struct hda_codec *codec,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014899 const struct alc_fixup *fix, int action)
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014900{
14901 int coef;
14902
Takashi Iwai58701122011-01-13 15:41:45 +010014903 if (action != ALC_FIXUP_ACT_INIT)
Takashi Iwai9fb1ef22011-01-13 14:40:43 +010014904 return;
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014905 coef = alc_read_coef_idx(codec, 0x1e);
14906 alc_write_coef_idx(codec, 0x1e, coef | 0x80);
14907}
14908
Takashi Iwaiff818c22010-04-12 08:59:25 +020014909enum {
14910 ALC269_FIXUP_SONY_VAIO,
Takashi Iwai74dc8902011-01-13 14:14:41 +010014911 ALC275_FIXUP_SONY_VAIO_GPIO2,
David Henningsson145a9022010-09-16 10:07:53 +020014912 ALC269_FIXUP_DELL_M101Z,
David Henningsson022c92b2010-12-17 20:43:04 +010014913 ALC269_FIXUP_SKU_IGNORE,
David Henningssonac612402010-12-15 09:18:18 +010014914 ALC269_FIXUP_ASUS_G73JW,
Kailang Yang357f9152011-01-12 08:12:52 +010014915 ALC269_FIXUP_LENOVO_EAPD,
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014916 ALC275_FIXUP_SONY_HWEQ,
Takashi Iwaiff818c22010-04-12 08:59:25 +020014917};
14918
Takashi Iwaiff818c22010-04-12 08:59:25 +020014919static const struct alc_fixup alc269_fixups[] = {
14920 [ALC269_FIXUP_SONY_VAIO] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014921 .type = ALC_FIXUP_VERBS,
14922 .v.verbs = (const struct hda_verb[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020014923 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
14924 {}
14925 }
Takashi Iwaiff818c22010-04-12 08:59:25 +020014926 },
Takashi Iwai74dc8902011-01-13 14:14:41 +010014927 [ALC275_FIXUP_SONY_VAIO_GPIO2] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014928 .type = ALC_FIXUP_VERBS,
14929 .v.verbs = (const struct hda_verb[]) {
Kailang Yang27855912010-12-21 09:09:53 +010014930 {0x01, AC_VERB_SET_GPIO_MASK, 0x04},
14931 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04},
14932 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
14933 { }
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014934 },
14935 .chained = true,
14936 .chain_id = ALC269_FIXUP_SONY_VAIO
Kailang Yang27855912010-12-21 09:09:53 +010014937 },
David Henningsson145a9022010-09-16 10:07:53 +020014938 [ALC269_FIXUP_DELL_M101Z] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014939 .type = ALC_FIXUP_VERBS,
14940 .v.verbs = (const struct hda_verb[]) {
David Henningsson145a9022010-09-16 10:07:53 +020014941 /* Enables internal speaker */
14942 {0x20, AC_VERB_SET_COEF_INDEX, 13},
14943 {0x20, AC_VERB_SET_PROC_COEF, 0x4040},
14944 {}
14945 }
14946 },
David Henningsson022c92b2010-12-17 20:43:04 +010014947 [ALC269_FIXUP_SKU_IGNORE] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014948 .type = ALC_FIXUP_SKU,
14949 .v.sku = ALC_FIXUP_SKU_IGNORE,
David Henningssonfe67b242010-12-15 08:01:46 +010014950 },
David Henningssonac612402010-12-15 09:18:18 +010014951 [ALC269_FIXUP_ASUS_G73JW] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014952 .type = ALC_FIXUP_PINS,
14953 .v.pins = (const struct alc_pincfg[]) {
David Henningssonac612402010-12-15 09:18:18 +010014954 { 0x17, 0x99130111 }, /* subwoofer */
14955 { }
14956 }
14957 },
Kailang Yang357f9152011-01-12 08:12:52 +010014958 [ALC269_FIXUP_LENOVO_EAPD] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014959 .type = ALC_FIXUP_VERBS,
14960 .v.verbs = (const struct hda_verb[]) {
Kailang Yang357f9152011-01-12 08:12:52 +010014961 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
14962 {}
14963 }
14964 },
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014965 [ALC275_FIXUP_SONY_HWEQ] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014966 .type = ALC_FIXUP_FUNC,
14967 .v.func = alc269_fixup_hweq,
14968 .chained = true,
14969 .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014970 }
Takashi Iwaiff818c22010-04-12 08:59:25 +020014971};
14972
14973static struct snd_pci_quirk alc269_fixup_tbl[] = {
Takashi Iwai74dc8902011-01-13 14:14:41 +010014974 SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014975 SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
14976 SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
Takashi Iwai7039c742010-12-23 16:35:34 +010014977 SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
David Henningsson145a9022010-09-16 10:07:53 +020014978 SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
David Henningsson022c92b2010-12-17 20:43:04 +010014979 SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
David Henningssonded9f522011-01-26 11:46:12 +010014980 SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
14981 SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
14982 SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE),
14983 SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE),
David Henningssonac612402010-12-15 09:18:18 +010014984 SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
Kailang Yang357f9152011-01-12 08:12:52 +010014985 SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
Takashi Iwaiff818c22010-04-12 08:59:25 +020014986 {}
14987};
14988
14989
Kailang Yangf6a92242007-12-13 16:52:54 +010014990/*
14991 * configuration and preset
14992 */
Takashi Iwaiea734962011-01-17 11:29:34 +010014993static const char * const alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014994 [ALC269_BASIC] = "basic",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020014995 [ALC269_QUANTA_FL1] = "quanta",
Kailang Yang84898e82010-02-04 14:16:14 +010014996 [ALC269_AMIC] = "laptop-amic",
14997 [ALC269_DMIC] = "laptop-dmic",
Tony Vroon64154832008-11-06 15:08:49 +000014998 [ALC269_FUJITSU] = "fujitsu",
Takashi Iwai3d3792c2009-09-11 07:50:47 +020014999 [ALC269_LIFEBOOK] = "lifebook",
15000 [ALC269_AUTO] = "auto",
Kailang Yangf6a92242007-12-13 16:52:54 +010015001};
15002
15003static struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020015004 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020015005 SND_PCI_QUIRK(0x1025, 0x047c, "ACER ZGA", ALC271_ACER),
Kailang Yangf53281e2008-07-18 12:36:43 +020015006 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
Kailang Yang84898e82010-02-04 14:16:14 +010015007 ALC269_AMIC),
15008 SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC),
15009 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC),
15010 SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC),
15011 SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC),
15012 SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC),
15013 SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC),
15014 SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC),
15015 SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC),
15016 SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC),
15017 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82Jv", ALC269_AMIC),
15018 SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC),
15019 SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC),
15020 SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC),
15021 SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC),
15022 SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC),
15023 SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC),
15024 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC),
15025 SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC),
15026 SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC),
15027 SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC),
15028 SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC),
15029 SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC),
15030 SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC),
15031 SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC),
15032 SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC),
15033 SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC),
15034 SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC),
15035 SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC),
15036 SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC),
15037 SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC),
15038 SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC),
15039 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC),
15040 SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC),
15041 SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC),
15042 SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC),
15043 SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC),
Kailang Yangf53281e2008-07-18 12:36:43 +020015044 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
Kailang Yang84898e82010-02-04 14:16:14 +010015045 ALC269_DMIC),
Kailang Yang60db6b52008-08-26 13:13:00 +020015046 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
Kailang Yang84898e82010-02-04 14:16:14 +010015047 ALC269_DMIC),
15048 SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC),
15049 SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC),
Takashi Iwaiff818c22010-04-12 08:59:25 +020015050 SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_AUTO),
Tony Vroon64154832008-11-06 15:08:49 +000015051 SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
Kailang Yang61c2d2b2010-02-25 08:49:06 +010015052 SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC),
15053 SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
15054 SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_AMIC),
15055 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_AMIC),
15056 SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_DMIC),
15057 SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_DMIC),
Kailang Yangf6a92242007-12-13 16:52:54 +010015058 {}
15059};
15060
15061static struct alc_config_preset alc269_presets[] = {
15062 [ALC269_BASIC] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015063 .mixers = { alc269_base_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010015064 .init_verbs = { alc269_init_verbs },
15065 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15066 .dac_nids = alc269_dac_nids,
15067 .hp_nid = 0x03,
15068 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15069 .channel_mode = alc269_modes,
15070 .input_mux = &alc269_capture_source,
15071 },
Kailang Yang60db6b52008-08-26 13:13:00 +020015072 [ALC269_QUANTA_FL1] = {
15073 .mixers = { alc269_quanta_fl1_mixer },
15074 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
15075 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15076 .dac_nids = alc269_dac_nids,
15077 .hp_nid = 0x03,
15078 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15079 .channel_mode = alc269_modes,
15080 .input_mux = &alc269_capture_source,
15081 .unsol_event = alc269_quanta_fl1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020015082 .setup = alc269_quanta_fl1_setup,
Kailang Yang60db6b52008-08-26 13:13:00 +020015083 .init_hook = alc269_quanta_fl1_init_hook,
15084 },
Kailang Yang84898e82010-02-04 14:16:14 +010015085 [ALC269_AMIC] = {
15086 .mixers = { alc269_laptop_mixer },
15087 .cap_mixer = alc269_laptop_analog_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020015088 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010015089 alc269_laptop_amic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020015090 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15091 .dac_nids = alc269_dac_nids,
15092 .hp_nid = 0x03,
15093 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15094 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010015095 .unsol_event = alc269_laptop_unsol_event,
15096 .setup = alc269_laptop_amic_setup,
15097 .init_hook = alc269_laptop_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020015098 },
Kailang Yang84898e82010-02-04 14:16:14 +010015099 [ALC269_DMIC] = {
15100 .mixers = { alc269_laptop_mixer },
15101 .cap_mixer = alc269_laptop_digital_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020015102 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010015103 alc269_laptop_dmic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020015104 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15105 .dac_nids = alc269_dac_nids,
15106 .hp_nid = 0x03,
15107 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15108 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010015109 .unsol_event = alc269_laptop_unsol_event,
15110 .setup = alc269_laptop_dmic_setup,
15111 .init_hook = alc269_laptop_inithook,
15112 },
15113 [ALC269VB_AMIC] = {
15114 .mixers = { alc269vb_laptop_mixer },
15115 .cap_mixer = alc269vb_laptop_analog_capture_mixer,
15116 .init_verbs = { alc269vb_init_verbs,
15117 alc269vb_laptop_amic_init_verbs },
15118 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15119 .dac_nids = alc269_dac_nids,
15120 .hp_nid = 0x03,
15121 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15122 .channel_mode = alc269_modes,
15123 .unsol_event = alc269_laptop_unsol_event,
Kailang Yang226b1ec2010-04-09 11:01:20 +020015124 .setup = alc269vb_laptop_amic_setup,
Kailang Yang84898e82010-02-04 14:16:14 +010015125 .init_hook = alc269_laptop_inithook,
15126 },
15127 [ALC269VB_DMIC] = {
15128 .mixers = { alc269vb_laptop_mixer },
15129 .cap_mixer = alc269vb_laptop_digital_capture_mixer,
15130 .init_verbs = { alc269vb_init_verbs,
15131 alc269vb_laptop_dmic_init_verbs },
15132 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15133 .dac_nids = alc269_dac_nids,
15134 .hp_nid = 0x03,
15135 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15136 .channel_mode = alc269_modes,
15137 .unsol_event = alc269_laptop_unsol_event,
15138 .setup = alc269vb_laptop_dmic_setup,
15139 .init_hook = alc269_laptop_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020015140 },
Takashi Iwai26f5df22008-11-03 17:39:46 +010015141 [ALC269_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010015142 .mixers = { alc269_fujitsu_mixer },
Kailang Yang84898e82010-02-04 14:16:14 +010015143 .cap_mixer = alc269_laptop_digital_capture_mixer,
Takashi Iwai26f5df22008-11-03 17:39:46 +010015144 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010015145 alc269_laptop_dmic_init_verbs },
Takashi Iwai26f5df22008-11-03 17:39:46 +010015146 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15147 .dac_nids = alc269_dac_nids,
15148 .hp_nid = 0x03,
15149 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15150 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010015151 .unsol_event = alc269_laptop_unsol_event,
15152 .setup = alc269_laptop_dmic_setup,
15153 .init_hook = alc269_laptop_inithook,
Takashi Iwai26f5df22008-11-03 17:39:46 +010015154 },
Tony Vroon64154832008-11-06 15:08:49 +000015155 [ALC269_LIFEBOOK] = {
15156 .mixers = { alc269_lifebook_mixer },
15157 .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
15158 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15159 .dac_nids = alc269_dac_nids,
15160 .hp_nid = 0x03,
15161 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15162 .channel_mode = alc269_modes,
15163 .input_mux = &alc269_capture_source,
15164 .unsol_event = alc269_lifebook_unsol_event,
15165 .init_hook = alc269_lifebook_init_hook,
15166 },
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020015167 [ALC271_ACER] = {
15168 .mixers = { alc269_asus_mixer },
15169 .cap_mixer = alc269vb_laptop_digital_capture_mixer,
15170 .init_verbs = { alc269_init_verbs, alc271_acer_dmic_verbs },
15171 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15172 .dac_nids = alc269_dac_nids,
15173 .adc_nids = alc262_dmic_adc_nids,
15174 .num_adc_nids = ARRAY_SIZE(alc262_dmic_adc_nids),
15175 .capsrc_nids = alc262_dmic_capsrc_nids,
15176 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15177 .channel_mode = alc269_modes,
15178 .input_mux = &alc269_capture_source,
15179 .dig_out_nid = ALC880_DIGOUT_NID,
15180 .unsol_event = alc_sku_unsol_event,
15181 .setup = alc269vb_laptop_dmic_setup,
15182 .init_hook = alc_inithook,
15183 },
Kailang Yangf6a92242007-12-13 16:52:54 +010015184};
15185
Kailang Yang977ddd62010-09-15 10:02:29 +020015186static int alc269_fill_coef(struct hda_codec *codec)
15187{
15188 int val;
15189
15190 if ((alc_read_coef_idx(codec, 0) & 0x00ff) < 0x015) {
15191 alc_write_coef_idx(codec, 0xf, 0x960b);
15192 alc_write_coef_idx(codec, 0xe, 0x8817);
15193 }
15194
15195 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x016) {
15196 alc_write_coef_idx(codec, 0xf, 0x960b);
15197 alc_write_coef_idx(codec, 0xe, 0x8814);
15198 }
15199
15200 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
15201 val = alc_read_coef_idx(codec, 0x04);
15202 /* Power up output pin */
15203 alc_write_coef_idx(codec, 0x04, val | (1<<11));
15204 }
15205
15206 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
15207 val = alc_read_coef_idx(codec, 0xd);
15208 if ((val & 0x0c00) >> 10 != 0x1) {
15209 /* Capless ramp up clock control */
15210 alc_write_coef_idx(codec, 0xd, val | 1<<10);
15211 }
15212 val = alc_read_coef_idx(codec, 0x17);
15213 if ((val & 0x01c0) >> 6 != 0x4) {
15214 /* Class D power on reset */
15215 alc_write_coef_idx(codec, 0x17, val | 1<<7);
15216 }
15217 }
15218 return 0;
15219}
15220
Kailang Yangf6a92242007-12-13 16:52:54 +010015221static int patch_alc269(struct hda_codec *codec)
15222{
15223 struct alc_spec *spec;
Kailang Yang48c88e82010-11-23 08:56:16 +010015224 int board_config, coef;
Kailang Yangf6a92242007-12-13 16:52:54 +010015225 int err;
15226
15227 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
15228 if (spec == NULL)
15229 return -ENOMEM;
15230
15231 codec->spec = spec;
15232
Kailang Yangda00c242010-03-19 11:23:45 +010015233 alc_auto_parse_customize_define(codec);
15234
Kailang Yangc793bec2010-12-21 09:14:13 +010015235 if (codec->vendor_id == 0x10ec0269) {
15236 coef = alc_read_coef_idx(codec, 0);
15237 if ((coef & 0x00f0) == 0x0010) {
15238 if (codec->bus->pci->subsystem_vendor == 0x1025 &&
15239 spec->cdefine.platform_type == 1) {
15240 alc_codec_rename(codec, "ALC271X");
15241 spec->codec_variant = ALC269_TYPE_ALC271X;
15242 } else if ((coef & 0xf000) == 0x1000) {
15243 spec->codec_variant = ALC269_TYPE_ALC270;
15244 } else if ((coef & 0xf000) == 0x2000) {
15245 alc_codec_rename(codec, "ALC259");
15246 spec->codec_variant = ALC269_TYPE_ALC259;
15247 } else if ((coef & 0xf000) == 0x3000) {
15248 alc_codec_rename(codec, "ALC258");
15249 spec->codec_variant = ALC269_TYPE_ALC258;
15250 } else {
15251 alc_codec_rename(codec, "ALC269VB");
15252 spec->codec_variant = ALC269_TYPE_ALC269VB;
15253 }
15254 } else
15255 alc_fix_pll_init(codec, 0x20, 0x04, 15);
15256 alc269_fill_coef(codec);
15257 }
Kailang Yang977ddd62010-09-15 10:02:29 +020015258
Kailang Yangf6a92242007-12-13 16:52:54 +010015259 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
15260 alc269_models,
15261 alc269_cfg_tbl);
15262
15263 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020015264 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
15265 codec->chip_name);
Kailang Yangf6a92242007-12-13 16:52:54 +010015266 board_config = ALC269_AUTO;
15267 }
15268
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010015269 if (board_config == ALC269_AUTO) {
15270 alc_pick_fixup(codec, NULL, alc269_fixup_tbl, alc269_fixups);
15271 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
15272 }
Takashi Iwaiff818c22010-04-12 08:59:25 +020015273
Kailang Yangf6a92242007-12-13 16:52:54 +010015274 if (board_config == ALC269_AUTO) {
15275 /* automatic parse from the BIOS config */
15276 err = alc269_parse_auto_config(codec);
15277 if (err < 0) {
15278 alc_free(codec);
15279 return err;
15280 } else if (!err) {
15281 printk(KERN_INFO
15282 "hda_codec: Cannot set up configuration "
15283 "from BIOS. Using base mode...\n");
15284 board_config = ALC269_BASIC;
15285 }
15286 }
15287
Takashi Iwaidc1eae22010-07-29 15:30:02 +020015288 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020015289 err = snd_hda_attach_beep_device(codec, 0x1);
15290 if (err < 0) {
15291 alc_free(codec);
15292 return err;
15293 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090015294 }
15295
Kailang Yangf6a92242007-12-13 16:52:54 +010015296 if (board_config != ALC269_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020015297 setup_preset(codec, &alc269_presets[board_config]);
Kailang Yangf6a92242007-12-13 16:52:54 +010015298
Kailang Yang84898e82010-02-04 14:16:14 +010015299 if (board_config == ALC269_QUANTA_FL1) {
Takashi Iwaif03d3112009-03-05 14:18:16 +010015300 /* Due to a hardware problem on Lenovo Ideadpad, we need to
15301 * fix the sample rate of analog I/O to 44.1kHz
15302 */
15303 spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
15304 spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
Takashi Iwai840b64c2010-07-13 22:49:01 +020015305 } else if (spec->dual_adc_switch) {
15306 spec->stream_analog_playback = &alc269_pcm_analog_playback;
15307 /* switch ADC dynamically */
15308 spec->stream_analog_capture = &dualmic_pcm_analog_capture;
Takashi Iwaif03d3112009-03-05 14:18:16 +010015309 } else {
15310 spec->stream_analog_playback = &alc269_pcm_analog_playback;
15311 spec->stream_analog_capture = &alc269_pcm_analog_capture;
15312 }
Kailang Yangf6a92242007-12-13 16:52:54 +010015313 spec->stream_digital_playback = &alc269_pcm_digital_playback;
15314 spec->stream_digital_capture = &alc269_pcm_digital_capture;
15315
Takashi Iwai66946352010-03-29 17:21:45 +020015316 if (!spec->adc_nids) { /* wasn't filled automatically? use default */
Kailang Yang1657cbd2010-11-23 08:53:32 +010015317 if (spec->codec_variant == ALC269_TYPE_NORMAL) {
Takashi Iwai66946352010-03-29 17:21:45 +020015318 spec->adc_nids = alc269_adc_nids;
15319 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
15320 spec->capsrc_nids = alc269_capsrc_nids;
15321 } else {
15322 spec->adc_nids = alc269vb_adc_nids;
15323 spec->num_adc_nids = ARRAY_SIZE(alc269vb_adc_nids);
15324 spec->capsrc_nids = alc269vb_capsrc_nids;
15325 }
Kailang Yang84898e82010-02-04 14:16:14 +010015326 }
15327
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015328 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020015329 set_capture_mixer(codec);
Takashi Iwaidc1eae22010-07-29 15:30:02 +020015330 if (has_cdefine_beep(codec))
Kailang Yangda00c242010-03-19 11:23:45 +010015331 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Kailang Yangf6a92242007-12-13 16:52:54 +010015332
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010015333 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwaiff818c22010-04-12 08:59:25 +020015334
Takashi Iwai100d5eb2009-08-10 11:55:51 +020015335 spec->vmaster_nid = 0x02;
15336
Kailang Yangf6a92242007-12-13 16:52:54 +010015337 codec->patch_ops = alc_patch_ops;
Kailang Yang977ddd62010-09-15 10:02:29 +020015338#ifdef CONFIG_SND_HDA_POWER_SAVE
15339 codec->patch_ops.suspend = alc269_suspend;
15340#endif
15341#ifdef SND_HDA_NEEDS_RESUME
15342 codec->patch_ops.resume = alc269_resume;
15343#endif
Kailang Yangf6a92242007-12-13 16:52:54 +010015344 if (board_config == ALC269_AUTO)
15345 spec->init_hook = alc269_auto_init;
Kailang Yangbf1b0222010-10-21 08:49:56 +020015346
15347 alc_init_jacks(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010015348#ifdef CONFIG_SND_HDA_POWER_SAVE
15349 if (!spec->loopback.amplist)
15350 spec->loopback.amplist = alc269_loopbacks;
Takashi Iwaiad358792010-03-30 18:00:59 +020015351 if (alc269_mic2_for_mute_led(codec))
15352 codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps;
Kailang Yangf6a92242007-12-13 16:52:54 +010015353#endif
15354
15355 return 0;
15356}
15357
15358/*
Kailang Yangdf694da2005-12-05 19:42:22 +010015359 * ALC861 channel source setting (2/6 channel selection for 3-stack)
15360 */
15361
15362/*
15363 * set the path ways for 2 channel output
15364 * need to set the codec line out and mic 1 pin widgets to inputs
15365 */
15366static struct hda_verb alc861_threestack_ch2_init[] = {
15367 /* set pin widget 1Ah (line in) for input */
15368 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015369 /* set pin widget 18h (mic1/2) for input, for mic also enable
15370 * the vref
15371 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015372 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15373
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015374 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
15375#if 0
15376 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
15377 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
15378#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010015379 { } /* end */
15380};
15381/*
15382 * 6ch mode
15383 * need to set the codec line out and mic 1 pin widgets to outputs
15384 */
15385static struct hda_verb alc861_threestack_ch6_init[] = {
15386 /* set pin widget 1Ah (line in) for output (Back Surround)*/
15387 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15388 /* set pin widget 18h (mic1) for output (CLFE)*/
15389 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15390
15391 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015392 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015393
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015394 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
15395#if 0
15396 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
15397 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
15398#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010015399 { } /* end */
15400};
15401
15402static struct hda_channel_mode alc861_threestack_modes[2] = {
15403 { 2, alc861_threestack_ch2_init },
15404 { 6, alc861_threestack_ch6_init },
15405};
Takashi Iwai22309c32006-08-09 16:57:28 +020015406/* Set mic1 as input and unmute the mixer */
15407static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
15408 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15409 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
15410 { } /* end */
15411};
15412/* Set mic1 as output and mute mixer */
15413static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
15414 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15415 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
15416 { } /* end */
15417};
15418
15419static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
15420 { 2, alc861_uniwill_m31_ch2_init },
15421 { 4, alc861_uniwill_m31_ch4_init },
15422};
Kailang Yangdf694da2005-12-05 19:42:22 +010015423
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015424/* Set mic1 and line-in as input and unmute the mixer */
15425static struct hda_verb alc861_asus_ch2_init[] = {
15426 /* set pin widget 1Ah (line in) for input */
15427 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015428 /* set pin widget 18h (mic1/2) for input, for mic also enable
15429 * the vref
15430 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015431 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15432
15433 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
15434#if 0
15435 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
15436 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
15437#endif
15438 { } /* end */
15439};
15440/* Set mic1 nad line-in as output and mute mixer */
15441static struct hda_verb alc861_asus_ch6_init[] = {
15442 /* set pin widget 1Ah (line in) for output (Back Surround)*/
15443 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15444 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
15445 /* set pin widget 18h (mic1) for output (CLFE)*/
15446 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15447 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
15448 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
15449 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
15450
15451 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
15452#if 0
15453 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
15454 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
15455#endif
15456 { } /* end */
15457};
15458
15459static struct hda_channel_mode alc861_asus_modes[2] = {
15460 { 2, alc861_asus_ch2_init },
15461 { 6, alc861_asus_ch6_init },
15462};
15463
Kailang Yangdf694da2005-12-05 19:42:22 +010015464/* patch-ALC861 */
15465
15466static struct snd_kcontrol_new alc861_base_mixer[] = {
15467 /* output mixer control */
15468 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15469 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15470 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15471 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15472 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
15473
15474 /*Input mixer control */
15475 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15476 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
15477 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15478 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15479 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15480 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15481 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15482 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15483 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
15484 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015485
Kailang Yangdf694da2005-12-05 19:42:22 +010015486 { } /* end */
15487};
15488
15489static struct snd_kcontrol_new alc861_3ST_mixer[] = {
15490 /* output mixer control */
15491 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15492 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15493 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15494 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15495 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
15496
15497 /* Input mixer control */
15498 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15499 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
15500 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15501 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15502 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15503 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15504 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15505 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15506 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
15507 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015508
Kailang Yangdf694da2005-12-05 19:42:22 +010015509 {
15510 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15511 .name = "Channel Mode",
15512 .info = alc_ch_mode_info,
15513 .get = alc_ch_mode_get,
15514 .put = alc_ch_mode_put,
15515 .private_value = ARRAY_SIZE(alc861_threestack_modes),
15516 },
15517 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015518};
15519
Takashi Iwaid1d985f2006-11-23 19:27:12 +010015520static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015521 /* output mixer control */
15522 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15523 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15524 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020015525
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015526 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015527};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015528
Takashi Iwai22309c32006-08-09 16:57:28 +020015529static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
15530 /* output mixer control */
15531 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15532 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15533 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15534 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15535 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
15536
15537 /* Input mixer control */
15538 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15539 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
15540 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15541 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15542 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15543 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15544 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15545 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15546 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
15547 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015548
Takashi Iwai22309c32006-08-09 16:57:28 +020015549 {
15550 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15551 .name = "Channel Mode",
15552 .info = alc_ch_mode_info,
15553 .get = alc_ch_mode_get,
15554 .put = alc_ch_mode_put,
15555 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
15556 },
15557 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015558};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015559
15560static struct snd_kcontrol_new alc861_asus_mixer[] = {
15561 /* output mixer control */
15562 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15563 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15564 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15565 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15566 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
15567
15568 /* Input mixer control */
15569 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15570 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
15571 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15572 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15573 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15574 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15575 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15576 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15577 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015578 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
15579
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015580 {
15581 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15582 .name = "Channel Mode",
15583 .info = alc_ch_mode_info,
15584 .get = alc_ch_mode_get,
15585 .put = alc_ch_mode_put,
15586 .private_value = ARRAY_SIZE(alc861_asus_modes),
15587 },
15588 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015589};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015590
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015591/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010015592static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015593 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15594 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015595 { }
15596};
15597
Kailang Yangdf694da2005-12-05 19:42:22 +010015598/*
15599 * generic initialization of ADC, input mixers and output mixers
15600 */
15601static struct hda_verb alc861_base_init_verbs[] = {
15602 /*
15603 * Unmute ADC0 and set the default input to mic-in
15604 */
15605 /* port-A for surround (rear panel) */
15606 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15607 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
15608 /* port-B for mic-in (rear panel) with vref */
15609 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15610 /* port-C for line-in (rear panel) */
15611 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15612 /* port-D for Front */
15613 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15614 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15615 /* port-E for HP out (front panel) */
15616 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
15617 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015618 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015619 /* port-F for mic-in (front panel) with vref */
15620 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15621 /* port-G for CLFE (rear panel) */
15622 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15623 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
15624 /* port-H for side (rear panel) */
15625 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15626 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
15627 /* CD-in */
15628 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15629 /* route front mic to ADC1*/
15630 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15631 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015632
Kailang Yangdf694da2005-12-05 19:42:22 +010015633 /* Unmute DAC0~3 & spdif out*/
15634 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15635 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15636 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15637 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15638 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015639
Kailang Yangdf694da2005-12-05 19:42:22 +010015640 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15641 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15642 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15643 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15644 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015645
Kailang Yangdf694da2005-12-05 19:42:22 +010015646 /* Unmute Stereo Mixer 15 */
15647 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15648 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15649 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015650 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015651
15652 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15653 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15654 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15655 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15656 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15657 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15658 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15659 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015660 /* hp used DAC 3 (Front) */
15661 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015662 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15663
15664 { }
15665};
15666
15667static struct hda_verb alc861_threestack_init_verbs[] = {
15668 /*
15669 * Unmute ADC0 and set the default input to mic-in
15670 */
15671 /* port-A for surround (rear panel) */
15672 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15673 /* port-B for mic-in (rear panel) with vref */
15674 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15675 /* port-C for line-in (rear panel) */
15676 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15677 /* port-D for Front */
15678 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15679 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15680 /* port-E for HP out (front panel) */
15681 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
15682 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015683 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015684 /* port-F for mic-in (front panel) with vref */
15685 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15686 /* port-G for CLFE (rear panel) */
15687 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15688 /* port-H for side (rear panel) */
15689 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15690 /* CD-in */
15691 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15692 /* route front mic to ADC1*/
15693 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15694 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15695 /* Unmute DAC0~3 & spdif out*/
15696 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15697 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15698 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15699 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15700 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015701
Kailang Yangdf694da2005-12-05 19:42:22 +010015702 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15703 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15704 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15705 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15706 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015707
Kailang Yangdf694da2005-12-05 19:42:22 +010015708 /* Unmute Stereo Mixer 15 */
15709 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15710 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15711 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015712 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015713
15714 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15715 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15716 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15717 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15718 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15719 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15720 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15721 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015722 /* hp used DAC 3 (Front) */
15723 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015724 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15725 { }
15726};
Takashi Iwai22309c32006-08-09 16:57:28 +020015727
15728static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
15729 /*
15730 * Unmute ADC0 and set the default input to mic-in
15731 */
15732 /* port-A for surround (rear panel) */
15733 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15734 /* port-B for mic-in (rear panel) with vref */
15735 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15736 /* port-C for line-in (rear panel) */
15737 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15738 /* port-D for Front */
15739 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15740 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15741 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015742 /* this has to be set to VREF80 */
15743 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015744 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015745 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015746 /* port-F for mic-in (front panel) with vref */
15747 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15748 /* port-G for CLFE (rear panel) */
15749 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15750 /* port-H for side (rear panel) */
15751 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15752 /* CD-in */
15753 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15754 /* route front mic to ADC1*/
15755 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15756 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15757 /* Unmute DAC0~3 & spdif out*/
15758 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15759 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15760 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15761 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15762 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015763
Takashi Iwai22309c32006-08-09 16:57:28 +020015764 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15765 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15766 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15767 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15768 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015769
Takashi Iwai22309c32006-08-09 16:57:28 +020015770 /* Unmute Stereo Mixer 15 */
15771 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15772 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15773 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015774 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020015775
15776 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15777 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15778 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15779 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15780 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15781 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15782 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15783 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015784 /* hp used DAC 3 (Front) */
15785 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020015786 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15787 { }
15788};
15789
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015790static struct hda_verb alc861_asus_init_verbs[] = {
15791 /*
15792 * Unmute ADC0 and set the default input to mic-in
15793 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015794 /* port-A for surround (rear panel)
15795 * according to codec#0 this is the HP jack
15796 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015797 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
15798 /* route front PCM to HP */
15799 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
15800 /* port-B for mic-in (rear panel) with vref */
15801 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15802 /* port-C for line-in (rear panel) */
15803 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15804 /* port-D for Front */
15805 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15806 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15807 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015808 /* this has to be set to VREF80 */
15809 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015810 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015811 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015812 /* port-F for mic-in (front panel) with vref */
15813 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15814 /* port-G for CLFE (rear panel) */
15815 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15816 /* port-H for side (rear panel) */
15817 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15818 /* CD-in */
15819 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15820 /* route front mic to ADC1*/
15821 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15822 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15823 /* Unmute DAC0~3 & spdif out*/
15824 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15825 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15826 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15827 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15828 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15829 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15830 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15831 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15832 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15833 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015834
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015835 /* Unmute Stereo Mixer 15 */
15836 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15837 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15838 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015839 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015840
15841 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15842 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15843 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15844 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15845 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15846 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15847 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15848 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015849 /* hp used DAC 3 (Front) */
15850 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015851 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15852 { }
15853};
15854
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015855/* additional init verbs for ASUS laptops */
15856static struct hda_verb alc861_asus_laptop_init_verbs[] = {
15857 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
15858 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
15859 { }
15860};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015861
Kailang Yangdf694da2005-12-05 19:42:22 +010015862/*
15863 * generic initialization of ADC, input mixers and output mixers
15864 */
15865static struct hda_verb alc861_auto_init_verbs[] = {
15866 /*
15867 * Unmute ADC0 and set the default input to mic-in
15868 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015869 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010015870 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015871
Kailang Yangdf694da2005-12-05 19:42:22 +010015872 /* Unmute DAC0~3 & spdif out*/
15873 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15874 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15875 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15876 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15877 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015878
Kailang Yangdf694da2005-12-05 19:42:22 +010015879 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15880 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15881 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15882 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15883 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015884
Kailang Yangdf694da2005-12-05 19:42:22 +010015885 /* Unmute Stereo Mixer 15 */
15886 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15887 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15888 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15889 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
15890
Takashi Iwai1c209302009-07-22 15:17:45 +020015891 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15892 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15893 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15894 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15895 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15896 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15897 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15898 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015899
15900 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15901 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020015902 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15903 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015904 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15905 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020015906 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15907 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015908
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015909 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015910
15911 { }
15912};
15913
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015914static struct hda_verb alc861_toshiba_init_verbs[] = {
15915 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015916
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015917 { }
15918};
15919
15920/* toggle speaker-output according to the hp-jack state */
15921static void alc861_toshiba_automute(struct hda_codec *codec)
15922{
Wu Fengguang864f92b2009-11-18 12:38:02 +080015923 unsigned int present = snd_hda_jack_detect(codec, 0x0f);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015924
Takashi Iwai47fd8302007-08-10 17:11:07 +020015925 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
15926 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
15927 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
15928 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015929}
15930
15931static void alc861_toshiba_unsol_event(struct hda_codec *codec,
15932 unsigned int res)
15933{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015934 if ((res >> 26) == ALC880_HP_EVENT)
15935 alc861_toshiba_automute(codec);
15936}
15937
Sasha Alexandrdef319f2009-06-16 16:00:15 -040015938/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015939#define alc861_pcm_analog_playback alc880_pcm_analog_playback
15940#define alc861_pcm_analog_capture alc880_pcm_analog_capture
15941#define alc861_pcm_digital_playback alc880_pcm_digital_playback
15942#define alc861_pcm_digital_capture alc880_pcm_digital_capture
15943
15944
15945#define ALC861_DIGOUT_NID 0x07
15946
15947static struct hda_channel_mode alc861_8ch_modes[1] = {
15948 { 8, NULL }
15949};
15950
15951static hda_nid_t alc861_dac_nids[4] = {
15952 /* front, surround, clfe, side */
15953 0x03, 0x06, 0x05, 0x04
15954};
15955
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015956static hda_nid_t alc660_dac_nids[3] = {
15957 /* front, clfe, surround */
15958 0x03, 0x05, 0x06
15959};
15960
Kailang Yangdf694da2005-12-05 19:42:22 +010015961static hda_nid_t alc861_adc_nids[1] = {
15962 /* ADC0-2 */
15963 0x08,
15964};
15965
15966static struct hda_input_mux alc861_capture_source = {
15967 .num_items = 5,
15968 .items = {
15969 { "Mic", 0x0 },
15970 { "Front Mic", 0x3 },
15971 { "Line", 0x1 },
15972 { "CD", 0x4 },
15973 { "Mixer", 0x5 },
15974 },
15975};
15976
Takashi Iwai1c209302009-07-22 15:17:45 +020015977static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
15978{
15979 struct alc_spec *spec = codec->spec;
15980 hda_nid_t mix, srcs[5];
15981 int i, j, num;
15982
15983 if (snd_hda_get_connections(codec, pin, &mix, 1) != 1)
15984 return 0;
15985 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
15986 if (num < 0)
15987 return 0;
15988 for (i = 0; i < num; i++) {
15989 unsigned int type;
Takashi Iwaia22d5432009-07-27 12:54:26 +020015990 type = get_wcaps_type(get_wcaps(codec, srcs[i]));
Takashi Iwai1c209302009-07-22 15:17:45 +020015991 if (type != AC_WID_AUD_OUT)
15992 continue;
15993 for (j = 0; j < spec->multiout.num_dacs; j++)
15994 if (spec->multiout.dac_nids[j] == srcs[i])
15995 break;
15996 if (j >= spec->multiout.num_dacs)
15997 return srcs[i];
15998 }
15999 return 0;
16000}
16001
Kailang Yangdf694da2005-12-05 19:42:22 +010016002/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwai1c209302009-07-22 15:17:45 +020016003static int alc861_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016004 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010016005{
Takashi Iwai1c209302009-07-22 15:17:45 +020016006 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010016007 int i;
Takashi Iwai1c209302009-07-22 15:17:45 +020016008 hda_nid_t nid, dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010016009
16010 spec->multiout.dac_nids = spec->private_dac_nids;
16011 for (i = 0; i < cfg->line_outs; i++) {
16012 nid = cfg->line_out_pins[i];
Takashi Iwai1c209302009-07-22 15:17:45 +020016013 dac = alc861_look_for_dac(codec, nid);
16014 if (!dac)
16015 continue;
16016 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010016017 }
Kailang Yangdf694da2005-12-05 19:42:22 +010016018 return 0;
16019}
16020
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016021static int __alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
16022 hda_nid_t nid, int idx, unsigned int chs)
Kailang Yangdf694da2005-12-05 19:42:22 +010016023{
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016024 return __add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx, idx,
Takashi Iwai1c209302009-07-22 15:17:45 +020016025 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
16026}
16027
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016028#define alc861_create_out_sw(codec, pfx, nid, chs) \
16029 __alc861_create_out_sw(codec, pfx, nid, 0, chs)
16030
Takashi Iwai1c209302009-07-22 15:17:45 +020016031/* add playback controls from the parsed DAC table */
16032static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
16033 const struct auto_pin_cfg *cfg)
16034{
16035 struct alc_spec *spec = codec->spec;
Takashi Iwaiea734962011-01-17 11:29:34 +010016036 static const char * const chname[4] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016037 "Front", "Surround", NULL /*CLFE*/, "Side"
16038 };
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016039 const char *pfx = alc_get_line_out_pfx(cfg, true);
Kailang Yangdf694da2005-12-05 19:42:22 +010016040 hda_nid_t nid;
Takashi Iwai1c209302009-07-22 15:17:45 +020016041 int i, err;
16042
Kailang Yangdf694da2005-12-05 19:42:22 +010016043 for (i = 0; i < cfg->line_outs; i++) {
16044 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016045 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010016046 continue;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016047 if (!pfx && i == 2) {
Kailang Yangdf694da2005-12-05 19:42:22 +010016048 /* Center/LFE */
Takashi Iwai1c209302009-07-22 15:17:45 +020016049 err = alc861_create_out_sw(codec, "Center", nid, 1);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016050 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010016051 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020016052 err = alc861_create_out_sw(codec, "LFE", nid, 2);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016053 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010016054 return err;
16055 } else {
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016056 const char *name = pfx;
16057 if (!name)
16058 name = chname[i];
16059 err = __alc861_create_out_sw(codec, name, nid, i, 3);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016060 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010016061 return err;
16062 }
16063 }
16064 return 0;
16065}
16066
Takashi Iwai1c209302009-07-22 15:17:45 +020016067static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010016068{
Takashi Iwai1c209302009-07-22 15:17:45 +020016069 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010016070 int err;
16071 hda_nid_t nid;
16072
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016073 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010016074 return 0;
16075
16076 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
Takashi Iwai1c209302009-07-22 15:17:45 +020016077 nid = alc861_look_for_dac(codec, pin);
16078 if (nid) {
16079 err = alc861_create_out_sw(codec, "Headphone", nid, 3);
16080 if (err < 0)
16081 return err;
16082 spec->multiout.hp_nid = nid;
16083 }
Kailang Yangdf694da2005-12-05 19:42:22 +010016084 }
16085 return 0;
16086}
16087
16088/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020016089static int alc861_auto_create_input_ctls(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016090 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010016091{
Takashi Iwai05f5f472009-08-25 13:10:18 +020016092 return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x08, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010016093}
16094
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016095static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
16096 hda_nid_t nid,
Takashi Iwai1c209302009-07-22 15:17:45 +020016097 int pin_type, hda_nid_t dac)
Kailang Yangdf694da2005-12-05 19:42:22 +010016098{
Takashi Iwai1c209302009-07-22 15:17:45 +020016099 hda_nid_t mix, srcs[5];
16100 int i, num;
16101
Jacek Luczak564c5be2008-05-03 18:41:23 +020016102 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
16103 pin_type);
Takashi Iwai1c209302009-07-22 15:17:45 +020016104 snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Jacek Luczak564c5be2008-05-03 18:41:23 +020016105 AMP_OUT_UNMUTE);
Takashi Iwai1c209302009-07-22 15:17:45 +020016106 if (snd_hda_get_connections(codec, nid, &mix, 1) != 1)
16107 return;
16108 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
16109 if (num < 0)
16110 return;
16111 for (i = 0; i < num; i++) {
16112 unsigned int mute;
16113 if (srcs[i] == dac || srcs[i] == 0x15)
16114 mute = AMP_IN_UNMUTE(i);
16115 else
16116 mute = AMP_IN_MUTE(i);
16117 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
16118 mute);
16119 }
Kailang Yangdf694da2005-12-05 19:42:22 +010016120}
16121
16122static void alc861_auto_init_multi_out(struct hda_codec *codec)
16123{
16124 struct alc_spec *spec = codec->spec;
16125 int i;
16126
16127 for (i = 0; i < spec->autocfg.line_outs; i++) {
16128 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016129 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010016130 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016131 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016132 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010016133 }
16134}
16135
16136static void alc861_auto_init_hp_out(struct hda_codec *codec)
16137{
16138 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010016139
Takashi Iwai15870f02009-10-05 08:25:13 +020016140 if (spec->autocfg.hp_outs)
16141 alc861_auto_set_output_and_unmute(codec,
16142 spec->autocfg.hp_pins[0],
16143 PIN_HP,
Takashi Iwai1c209302009-07-22 15:17:45 +020016144 spec->multiout.hp_nid);
Takashi Iwai15870f02009-10-05 08:25:13 +020016145 if (spec->autocfg.speaker_outs)
16146 alc861_auto_set_output_and_unmute(codec,
16147 spec->autocfg.speaker_pins[0],
16148 PIN_OUT,
Takashi Iwai1c209302009-07-22 15:17:45 +020016149 spec->multiout.dac_nids[0]);
Kailang Yangdf694da2005-12-05 19:42:22 +010016150}
16151
16152static void alc861_auto_init_analog_input(struct hda_codec *codec)
16153{
16154 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020016155 struct auto_pin_cfg *cfg = &spec->autocfg;
Kailang Yangdf694da2005-12-05 19:42:22 +010016156 int i;
16157
Takashi Iwai66ceeb62010-08-30 13:05:52 +020016158 for (i = 0; i < cfg->num_inputs; i++) {
16159 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai23f0c042009-02-26 13:03:58 +010016160 if (nid >= 0x0c && nid <= 0x11)
Takashi Iwai30ea0982010-09-16 18:47:56 +020016161 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Kailang Yangdf694da2005-12-05 19:42:22 +010016162 }
16163}
16164
16165/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016166/* return 1 if successful, 0 if the proper config is not found,
16167 * or a negative error code
16168 */
Kailang Yangdf694da2005-12-05 19:42:22 +010016169static int alc861_parse_auto_config(struct hda_codec *codec)
16170{
16171 struct alc_spec *spec = codec->spec;
16172 int err;
16173 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
16174
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016175 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
16176 alc861_ignore);
16177 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010016178 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016179 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010016180 return 0; /* can't find valid BIOS pin config */
16181
Takashi Iwai1c209302009-07-22 15:17:45 +020016182 err = alc861_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016183 if (err < 0)
16184 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020016185 err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016186 if (err < 0)
16187 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020016188 err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016189 if (err < 0)
16190 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020016191 err = alc861_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016192 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010016193 return err;
16194
16195 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
16196
Takashi Iwai757899a2010-07-30 10:48:14 +020016197 alc_auto_parse_digital(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010016198
Takashi Iwai603c4012008-07-30 15:01:44 +020016199 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010016200 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010016201
Takashi Iwaid88897e2008-10-31 15:01:37 +010016202 add_verb(spec, alc861_auto_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +010016203
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020016204 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020016205 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010016206
16207 spec->adc_nids = alc861_adc_nids;
16208 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016209 set_capture_mixer(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010016210
Kailang Yang6227cdc2010-02-25 08:36:52 +010016211 alc_ssid_check(codec, 0x0e, 0x0f, 0x0b, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020016212
Kailang Yangdf694da2005-12-05 19:42:22 +010016213 return 1;
16214}
16215
Takashi Iwaiae6b8132006-03-03 16:47:17 +010016216/* additional initialization for auto-configuration model */
16217static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010016218{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016219 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010016220 alc861_auto_init_multi_out(codec);
16221 alc861_auto_init_hp_out(codec);
16222 alc861_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020016223 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016224 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020016225 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010016226}
16227
Takashi Iwaicb53c622007-08-10 17:21:45 +020016228#ifdef CONFIG_SND_HDA_POWER_SAVE
16229static struct hda_amp_list alc861_loopbacks[] = {
16230 { 0x15, HDA_INPUT, 0 },
16231 { 0x15, HDA_INPUT, 1 },
16232 { 0x15, HDA_INPUT, 2 },
16233 { 0x15, HDA_INPUT, 3 },
16234 { } /* end */
16235};
16236#endif
16237
Kailang Yangdf694da2005-12-05 19:42:22 +010016238
16239/*
16240 * configuration and preset
16241 */
Takashi Iwaiea734962011-01-17 11:29:34 +010016242static const char * const alc861_models[ALC861_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010016243 [ALC861_3ST] = "3stack",
16244 [ALC660_3ST] = "3stack-660",
16245 [ALC861_3ST_DIG] = "3stack-dig",
16246 [ALC861_6ST_DIG] = "6stack-dig",
16247 [ALC861_UNIWILL_M31] = "uniwill-m31",
16248 [ALC861_TOSHIBA] = "toshiba",
16249 [ALC861_ASUS] = "asus",
16250 [ALC861_ASUS_LAPTOP] = "asus-laptop",
16251 [ALC861_AUTO] = "auto",
16252};
16253
16254static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010016255 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010016256 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
16257 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
16258 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016259 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020016260 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010016261 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020016262 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
16263 * Any other models that need this preset?
16264 */
16265 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020016266 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
16267 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016268 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
16269 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
16270 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
16271 /* FIXME: the below seems conflict */
16272 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
16273 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
16274 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010016275 {}
16276};
16277
16278static struct alc_config_preset alc861_presets[] = {
16279 [ALC861_3ST] = {
16280 .mixers = { alc861_3ST_mixer },
16281 .init_verbs = { alc861_threestack_init_verbs },
16282 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16283 .dac_nids = alc861_dac_nids,
16284 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
16285 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020016286 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010016287 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16288 .adc_nids = alc861_adc_nids,
16289 .input_mux = &alc861_capture_source,
16290 },
16291 [ALC861_3ST_DIG] = {
16292 .mixers = { alc861_base_mixer },
16293 .init_verbs = { alc861_threestack_init_verbs },
16294 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16295 .dac_nids = alc861_dac_nids,
16296 .dig_out_nid = ALC861_DIGOUT_NID,
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,
Kailang Yangdf694da2005-12-05 19:42:22 +010016300 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16301 .adc_nids = alc861_adc_nids,
16302 .input_mux = &alc861_capture_source,
16303 },
16304 [ALC861_6ST_DIG] = {
16305 .mixers = { alc861_base_mixer },
16306 .init_verbs = { alc861_base_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_8ch_modes),
16311 .channel_mode = alc861_8ch_modes,
16312 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16313 .adc_nids = alc861_adc_nids,
16314 .input_mux = &alc861_capture_source,
16315 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016316 [ALC660_3ST] = {
16317 .mixers = { alc861_3ST_mixer },
16318 .init_verbs = { alc861_threestack_init_verbs },
16319 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
16320 .dac_nids = alc660_dac_nids,
16321 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
16322 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020016323 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016324 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16325 .adc_nids = alc861_adc_nids,
16326 .input_mux = &alc861_capture_source,
16327 },
Takashi Iwai22309c32006-08-09 16:57:28 +020016328 [ALC861_UNIWILL_M31] = {
16329 .mixers = { alc861_uniwill_m31_mixer },
16330 .init_verbs = { alc861_uniwill_m31_init_verbs },
16331 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16332 .dac_nids = alc861_dac_nids,
16333 .dig_out_nid = ALC861_DIGOUT_NID,
16334 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
16335 .channel_mode = alc861_uniwill_m31_modes,
16336 .need_dac_fix = 1,
16337 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16338 .adc_nids = alc861_adc_nids,
16339 .input_mux = &alc861_capture_source,
16340 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020016341 [ALC861_TOSHIBA] = {
16342 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016343 .init_verbs = { alc861_base_init_verbs,
16344 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020016345 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16346 .dac_nids = alc861_dac_nids,
16347 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
16348 .channel_mode = alc883_3ST_2ch_modes,
16349 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16350 .adc_nids = alc861_adc_nids,
16351 .input_mux = &alc861_capture_source,
16352 .unsol_event = alc861_toshiba_unsol_event,
16353 .init_hook = alc861_toshiba_automute,
16354 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020016355 [ALC861_ASUS] = {
16356 .mixers = { alc861_asus_mixer },
16357 .init_verbs = { alc861_asus_init_verbs },
16358 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16359 .dac_nids = alc861_dac_nids,
16360 .dig_out_nid = ALC861_DIGOUT_NID,
16361 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
16362 .channel_mode = alc861_asus_modes,
16363 .need_dac_fix = 1,
16364 .hp_nid = 0x06,
16365 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16366 .adc_nids = alc861_adc_nids,
16367 .input_mux = &alc861_capture_source,
16368 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010016369 [ALC861_ASUS_LAPTOP] = {
16370 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
16371 .init_verbs = { alc861_asus_init_verbs,
16372 alc861_asus_laptop_init_verbs },
16373 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16374 .dac_nids = alc861_dac_nids,
16375 .dig_out_nid = ALC861_DIGOUT_NID,
16376 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
16377 .channel_mode = alc883_3ST_2ch_modes,
16378 .need_dac_fix = 1,
16379 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16380 .adc_nids = alc861_adc_nids,
16381 .input_mux = &alc861_capture_source,
16382 },
16383};
Kailang Yangdf694da2005-12-05 19:42:22 +010016384
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016385/* Pin config fixes */
16386enum {
16387 PINFIX_FSC_AMILO_PI1505,
16388};
16389
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016390static const struct alc_fixup alc861_fixups[] = {
16391 [PINFIX_FSC_AMILO_PI1505] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010016392 .type = ALC_FIXUP_PINS,
16393 .v.pins = (const struct alc_pincfg[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020016394 { 0x0b, 0x0221101f }, /* HP */
16395 { 0x0f, 0x90170310 }, /* speaker */
16396 { }
16397 }
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016398 },
16399};
16400
16401static struct snd_pci_quirk alc861_fixup_tbl[] = {
16402 SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
16403 {}
16404};
Kailang Yangdf694da2005-12-05 19:42:22 +010016405
16406static int patch_alc861(struct hda_codec *codec)
16407{
16408 struct alc_spec *spec;
16409 int board_config;
16410 int err;
16411
Robert P. J. Daydc041e02006-12-19 14:44:15 +010016412 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010016413 if (spec == NULL)
16414 return -ENOMEM;
16415
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016416 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010016417
Takashi Iwaif5fcc132006-11-24 17:07:44 +010016418 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
16419 alc861_models,
16420 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016421
Takashi Iwaif5fcc132006-11-24 17:07:44 +010016422 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020016423 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
16424 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010016425 board_config = ALC861_AUTO;
16426 }
16427
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010016428 if (board_config == ALC861_AUTO) {
16429 alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
16430 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
16431 }
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016432
Kailang Yangdf694da2005-12-05 19:42:22 +010016433 if (board_config == ALC861_AUTO) {
16434 /* automatic parse from the BIOS config */
16435 err = alc861_parse_auto_config(codec);
16436 if (err < 0) {
16437 alc_free(codec);
16438 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016439 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016440 printk(KERN_INFO
16441 "hda_codec: Cannot set up configuration "
16442 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010016443 board_config = ALC861_3ST_DIG;
16444 }
16445 }
16446
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090016447 err = snd_hda_attach_beep_device(codec, 0x23);
16448 if (err < 0) {
16449 alc_free(codec);
16450 return err;
16451 }
16452
Kailang Yangdf694da2005-12-05 19:42:22 +010016453 if (board_config != ALC861_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020016454 setup_preset(codec, &alc861_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010016455
Kailang Yangdf694da2005-12-05 19:42:22 +010016456 spec->stream_analog_playback = &alc861_pcm_analog_playback;
16457 spec->stream_analog_capture = &alc861_pcm_analog_capture;
16458
Kailang Yangdf694da2005-12-05 19:42:22 +010016459 spec->stream_digital_playback = &alc861_pcm_digital_playback;
16460 spec->stream_digital_capture = &alc861_pcm_digital_capture;
16461
Takashi Iwaic7a8eb12010-01-14 12:39:02 +010016462 if (!spec->cap_mixer)
16463 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010016464 set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
16465
Takashi Iwai2134ea42008-01-10 16:53:55 +010016466 spec->vmaster_nid = 0x03;
16467
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010016468 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwai7fa90e82010-04-12 08:49:00 +020016469
Kailang Yangdf694da2005-12-05 19:42:22 +010016470 codec->patch_ops = alc_patch_ops;
Daniel T Chenc97259d2009-12-27 18:52:08 -050016471 if (board_config == ALC861_AUTO) {
Takashi Iwaiae6b8132006-03-03 16:47:17 +010016472 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020016473#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050016474 spec->power_hook = alc_power_eapd;
16475#endif
16476 }
16477#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaicb53c622007-08-10 17:21:45 +020016478 if (!spec->loopback.amplist)
16479 spec->loopback.amplist = alc861_loopbacks;
16480#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020016481
Kailang Yangdf694da2005-12-05 19:42:22 +010016482 return 0;
16483}
16484
16485/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016486 * ALC861-VD support
16487 *
16488 * Based on ALC882
16489 *
16490 * In addition, an independent DAC
16491 */
16492#define ALC861VD_DIGOUT_NID 0x06
16493
16494static hda_nid_t alc861vd_dac_nids[4] = {
16495 /* front, surr, clfe, side surr */
16496 0x02, 0x03, 0x04, 0x05
16497};
16498
16499/* dac_nids for ALC660vd are in a different order - according to
16500 * Realtek's driver.
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016501 * This should probably result in a different mixer for 6stack models
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016502 * of ALC660vd codecs, but for now there is only 3stack mixer
16503 * - and it is the same as in 861vd.
16504 * adc_nids in ALC660vd are (is) the same as in 861vd
16505 */
16506static hda_nid_t alc660vd_dac_nids[3] = {
16507 /* front, rear, clfe, rear_surr */
16508 0x02, 0x04, 0x03
16509};
16510
16511static hda_nid_t alc861vd_adc_nids[1] = {
16512 /* ADC0 */
16513 0x09,
16514};
16515
Takashi Iwaie1406342008-02-11 18:32:32 +010016516static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
16517
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016518/* input MUX */
16519/* FIXME: should be a matrix-type input source selection */
16520static struct hda_input_mux alc861vd_capture_source = {
16521 .num_items = 4,
16522 .items = {
16523 { "Mic", 0x0 },
16524 { "Front Mic", 0x1 },
16525 { "Line", 0x2 },
16526 { "CD", 0x4 },
16527 },
16528};
16529
Kailang Yang272a5272007-05-14 11:00:38 +020016530static struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010016531 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020016532 .items = {
David Henningsson8607f7c2010-12-20 14:43:54 +010016533 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +010016534 { "Internal Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020016535 },
16536};
16537
Kailang Yangd1a991a2007-08-15 16:21:59 +020016538static struct hda_input_mux alc861vd_hp_capture_source = {
16539 .num_items = 2,
16540 .items = {
16541 { "Front Mic", 0x0 },
16542 { "ATAPI Mic", 0x1 },
16543 },
16544};
16545
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016546/*
16547 * 2ch mode
16548 */
16549static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
16550 { 2, NULL }
16551};
16552
16553/*
16554 * 6ch mode
16555 */
16556static struct hda_verb alc861vd_6stack_ch6_init[] = {
16557 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
16558 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16559 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16560 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16561 { } /* end */
16562};
16563
16564/*
16565 * 8ch mode
16566 */
16567static struct hda_verb alc861vd_6stack_ch8_init[] = {
16568 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16569 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16570 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16571 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16572 { } /* end */
16573};
16574
16575static struct hda_channel_mode alc861vd_6stack_modes[2] = {
16576 { 6, alc861vd_6stack_ch6_init },
16577 { 8, alc861vd_6stack_ch8_init },
16578};
16579
16580static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
16581 {
16582 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
16583 .name = "Channel Mode",
16584 .info = alc_ch_mode_info,
16585 .get = alc_ch_mode_get,
16586 .put = alc_ch_mode_put,
16587 },
16588 { } /* end */
16589};
16590
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016591/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
16592 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
16593 */
16594static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
16595 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16596 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16597
16598 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16599 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
16600
16601 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
16602 HDA_OUTPUT),
16603 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
16604 HDA_OUTPUT),
16605 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
16606 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
16607
16608 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
16609 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
16610
16611 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16612
David Henningsson5f99f862011-01-04 15:24:24 +010016613 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016614 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16615 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16616
David Henningsson5f99f862011-01-04 15:24:24 +010016617 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016618 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16619 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16620
16621 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16622 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16623
16624 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16625 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16626
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016627 { } /* end */
16628};
16629
16630static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
16631 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16632 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
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),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016637 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),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016641 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("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16645 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16646
16647 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16648 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16649
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016650 { } /* end */
16651};
16652
Kailang Yangbdd148a2007-05-08 15:19:08 +020016653static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
16654 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16655 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
16656 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
16657
16658 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16659
David Henningsson5f99f862011-01-04 15:24:24 +010016660 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +020016661 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16662 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16663
David Henningsson5f99f862011-01-04 15:24:24 +010016664 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +020016665 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16666 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16667
16668 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16669 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16670
16671 { } /* end */
16672};
16673
Tobin Davisb419f342008-03-07 11:57:51 +010016674/* Pin assignment: Speaker=0x14, HP = 0x15,
David Henningsson8607f7c2010-12-20 14:43:54 +010016675 * Mic=0x18, Internal Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020016676 */
16677static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010016678 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16679 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020016680 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16681 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010016682 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
David Henningsson8607f7c2010-12-20 14:43:54 +010016683 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16684 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010016685 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +010016686 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16687 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020016688 { } /* end */
16689};
16690
Kailang Yangd1a991a2007-08-15 16:21:59 +020016691/* Pin assignment: Speaker=0x14, Line-out = 0x15,
16692 * Front Mic=0x18, ATAPI Mic = 0x19,
16693 */
16694static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
16695 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16696 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16697 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16698 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
16699 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16700 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16701 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16702 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020016703
Kailang Yangd1a991a2007-08-15 16:21:59 +020016704 { } /* end */
16705};
16706
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016707/*
16708 * generic initialization of ADC, input mixers and output mixers
16709 */
16710static struct hda_verb alc861vd_volume_init_verbs[] = {
16711 /*
16712 * Unmute ADC0 and set the default input to mic-in
16713 */
16714 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
16715 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16716
16717 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
16718 * the analog-loopback mixer widget
16719 */
16720 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020016721 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16722 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16723 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16724 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16725 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016726
16727 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020016728 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16729 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16730 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016731 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016732
16733 /*
16734 * Set up output mixers (0x02 - 0x05)
16735 */
16736 /* set vol=0 to output mixers */
16737 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16738 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16739 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16740 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16741
16742 /* set up input amps for analog loopback */
16743 /* Amp Indices: DAC = 0, mixer = 1 */
16744 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16745 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16746 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16747 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16748 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16749 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16750 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16751 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16752
16753 { }
16754};
16755
16756/*
16757 * 3-stack pin configuration:
16758 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
16759 */
16760static struct hda_verb alc861vd_3stack_init_verbs[] = {
16761 /*
16762 * Set pin mode and muting
16763 */
16764 /* set front pin widgets 0x14 for output */
16765 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16766 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16767 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16768
16769 /* Mic (rear) pin: input vref at 80% */
16770 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16771 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16772 /* Front Mic pin: input vref at 80% */
16773 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16774 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16775 /* Line In pin: input */
16776 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16777 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16778 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16779 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16780 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16781 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16782 /* CD pin widget for input */
16783 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16784
16785 { }
16786};
16787
16788/*
16789 * 6-stack pin configuration:
16790 */
16791static struct hda_verb alc861vd_6stack_init_verbs[] = {
16792 /*
16793 * Set pin mode and muting
16794 */
16795 /* set front pin widgets 0x14 for output */
16796 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16797 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16798 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16799
16800 /* Rear Pin: output 1 (0x0d) */
16801 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16802 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16803 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
16804 /* CLFE Pin: output 2 (0x0e) */
16805 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16806 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16807 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
16808 /* Side Pin: output 3 (0x0f) */
16809 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16810 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16811 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
16812
16813 /* Mic (rear) pin: input vref at 80% */
16814 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16815 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16816 /* Front Mic pin: input vref at 80% */
16817 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16818 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16819 /* Line In pin: input */
16820 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16821 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16822 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16823 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16824 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16825 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16826 /* CD pin widget for input */
16827 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16828
16829 { }
16830};
16831
Kailang Yangbdd148a2007-05-08 15:19:08 +020016832static struct hda_verb alc861vd_eapd_verbs[] = {
16833 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16834 { }
16835};
16836
Kailang Yangf9423e72008-05-27 12:32:25 +020016837static struct hda_verb alc660vd_eapd_verbs[] = {
16838 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16839 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
16840 { }
16841};
16842
Kailang Yangbdd148a2007-05-08 15:19:08 +020016843static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
16844 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16845 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16846 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
16847 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020016848 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020016849 {}
16850};
16851
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016852static void alc861vd_lenovo_setup(struct hda_codec *codec)
Kailang Yangbdd148a2007-05-08 15:19:08 +020016853{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016854 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016855 spec->autocfg.hp_pins[0] = 0x1b;
16856 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016857}
16858
16859static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
16860{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016861 alc_automute_amp(codec);
Anisse Astiereeb43382010-12-16 12:19:47 +010016862 alc88x_simple_mic_automute(codec);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016863}
16864
16865static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
16866 unsigned int res)
16867{
16868 switch (res >> 26) {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016869 case ALC880_MIC_EVENT:
Anisse Astiereeb43382010-12-16 12:19:47 +010016870 alc88x_simple_mic_automute(codec);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016871 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016872 default:
16873 alc_automute_amp_unsol_event(codec, res);
16874 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +020016875 }
16876}
16877
Kailang Yang272a5272007-05-14 11:00:38 +020016878static struct hda_verb alc861vd_dallas_verbs[] = {
16879 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16880 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16881 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16882 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16883
16884 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16885 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16886 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16887 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16888 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16889 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16890 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16891 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016892
Kailang Yang272a5272007-05-14 11:00:38 +020016893 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16894 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16895 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16896 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16897 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16898 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16899 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16900 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16901
16902 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16903 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16904 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16905 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16906 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16907 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16908 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16909 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16910
16911 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16912 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16913 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16914 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
16915
16916 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016917 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020016918 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16919
16920 { } /* end */
16921};
16922
16923/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016924static void alc861vd_dallas_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +020016925{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016926 struct alc_spec *spec = codec->spec;
Kailang Yang272a5272007-05-14 11:00:38 +020016927
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016928 spec->autocfg.hp_pins[0] = 0x15;
16929 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang272a5272007-05-14 11:00:38 +020016930}
16931
Takashi Iwaicb53c622007-08-10 17:21:45 +020016932#ifdef CONFIG_SND_HDA_POWER_SAVE
16933#define alc861vd_loopbacks alc880_loopbacks
16934#endif
16935
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016936/* pcm configuration: identical with ALC880 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016937#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
16938#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
16939#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
16940#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
16941
16942/*
16943 * configuration and preset
16944 */
Takashi Iwaiea734962011-01-17 11:29:34 +010016945static const char * const alc861vd_models[ALC861VD_MODEL_LAST] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016946 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016947 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Takashi Iwai13c94742008-11-05 08:06:08 +010016948 [ALC660VD_ASUS_V1S] = "asus-v1s",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016949 [ALC861VD_3ST] = "3stack",
16950 [ALC861VD_3ST_DIG] = "3stack-digout",
16951 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020016952 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020016953 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016954 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016955 [ALC861VD_AUTO] = "auto",
16956};
16957
16958static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016959 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
16960 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010016961 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016962 /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */
Takashi Iwai13c94742008-11-05 08:06:08 +010016963 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
Mike Crash6963f842007-06-25 12:12:51 +020016964 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016965 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016966 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020016967 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Takashi Iwaice577e82009-08-03 08:23:52 +020016968 SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai542d7c62007-08-16 18:57:30 +020016969 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010016970 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020016971 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016972 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020016973 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016974 {}
16975};
16976
16977static struct alc_config_preset alc861vd_presets[] = {
16978 [ALC660VD_3ST] = {
16979 .mixers = { alc861vd_3st_mixer },
16980 .init_verbs = { alc861vd_volume_init_verbs,
16981 alc861vd_3stack_init_verbs },
16982 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16983 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016984 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16985 .channel_mode = alc861vd_3stack_2ch_modes,
16986 .input_mux = &alc861vd_capture_source,
16987 },
Mike Crash6963f842007-06-25 12:12:51 +020016988 [ALC660VD_3ST_DIG] = {
16989 .mixers = { alc861vd_3st_mixer },
16990 .init_verbs = { alc861vd_volume_init_verbs,
16991 alc861vd_3stack_init_verbs },
16992 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16993 .dac_nids = alc660vd_dac_nids,
16994 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020016995 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16996 .channel_mode = alc861vd_3stack_2ch_modes,
16997 .input_mux = &alc861vd_capture_source,
16998 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016999 [ALC861VD_3ST] = {
17000 .mixers = { alc861vd_3st_mixer },
17001 .init_verbs = { alc861vd_volume_init_verbs,
17002 alc861vd_3stack_init_verbs },
17003 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
17004 .dac_nids = alc861vd_dac_nids,
17005 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
17006 .channel_mode = alc861vd_3stack_2ch_modes,
17007 .input_mux = &alc861vd_capture_source,
17008 },
17009 [ALC861VD_3ST_DIG] = {
17010 .mixers = { alc861vd_3st_mixer },
17011 .init_verbs = { alc861vd_volume_init_verbs,
17012 alc861vd_3stack_init_verbs },
17013 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
17014 .dac_nids = alc861vd_dac_nids,
17015 .dig_out_nid = ALC861VD_DIGOUT_NID,
17016 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
17017 .channel_mode = alc861vd_3stack_2ch_modes,
17018 .input_mux = &alc861vd_capture_source,
17019 },
17020 [ALC861VD_6ST_DIG] = {
17021 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
17022 .init_verbs = { alc861vd_volume_init_verbs,
17023 alc861vd_6stack_init_verbs },
17024 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
17025 .dac_nids = alc861vd_dac_nids,
17026 .dig_out_nid = ALC861VD_DIGOUT_NID,
17027 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
17028 .channel_mode = alc861vd_6stack_modes,
17029 .input_mux = &alc861vd_capture_source,
17030 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020017031 [ALC861VD_LENOVO] = {
17032 .mixers = { alc861vd_lenovo_mixer },
17033 .init_verbs = { alc861vd_volume_init_verbs,
17034 alc861vd_3stack_init_verbs,
17035 alc861vd_eapd_verbs,
17036 alc861vd_lenovo_unsol_verbs },
17037 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
17038 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020017039 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
17040 .channel_mode = alc861vd_3stack_2ch_modes,
17041 .input_mux = &alc861vd_capture_source,
17042 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017043 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020017044 .init_hook = alc861vd_lenovo_init_hook,
Kailang Yangbdd148a2007-05-08 15:19:08 +020017045 },
Kailang Yang272a5272007-05-14 11:00:38 +020017046 [ALC861VD_DALLAS] = {
17047 .mixers = { alc861vd_dallas_mixer },
17048 .init_verbs = { alc861vd_dallas_verbs },
17049 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
17050 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020017051 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
17052 .channel_mode = alc861vd_3stack_2ch_modes,
17053 .input_mux = &alc861vd_dallas_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020017054 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017055 .setup = alc861vd_dallas_setup,
17056 .init_hook = alc_automute_amp,
Kailang Yangd1a991a2007-08-15 16:21:59 +020017057 },
17058 [ALC861VD_HP] = {
17059 .mixers = { alc861vd_hp_mixer },
17060 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
17061 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
17062 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020017063 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020017064 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
17065 .channel_mode = alc861vd_3stack_2ch_modes,
17066 .input_mux = &alc861vd_hp_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020017067 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017068 .setup = alc861vd_dallas_setup,
17069 .init_hook = alc_automute_amp,
Kailang Yangea1fb292008-08-26 12:58:38 +020017070 },
Takashi Iwai13c94742008-11-05 08:06:08 +010017071 [ALC660VD_ASUS_V1S] = {
17072 .mixers = { alc861vd_lenovo_mixer },
17073 .init_verbs = { alc861vd_volume_init_verbs,
17074 alc861vd_3stack_init_verbs,
17075 alc861vd_eapd_verbs,
17076 alc861vd_lenovo_unsol_verbs },
17077 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
17078 .dac_nids = alc660vd_dac_nids,
17079 .dig_out_nid = ALC861VD_DIGOUT_NID,
17080 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
17081 .channel_mode = alc861vd_3stack_2ch_modes,
17082 .input_mux = &alc861vd_capture_source,
17083 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017084 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020017085 .init_hook = alc861vd_lenovo_init_hook,
Takashi Iwai13c94742008-11-05 08:06:08 +010017086 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017087};
17088
17089/*
17090 * BIOS auto configuration
17091 */
Takashi Iwai05f5f472009-08-25 13:10:18 +020017092static int alc861vd_auto_create_input_ctls(struct hda_codec *codec,
17093 const struct auto_pin_cfg *cfg)
17094{
Herton Ronaldo Krzesinski71675942010-11-25 00:08:01 -020017095 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x22, 0);
Takashi Iwai05f5f472009-08-25 13:10:18 +020017096}
17097
17098
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017099static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
17100 hda_nid_t nid, int pin_type, int dac_idx)
17101{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017102 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017103}
17104
17105static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
17106{
17107 struct alc_spec *spec = codec->spec;
17108 int i;
17109
17110 for (i = 0; i <= HDA_SIDE; i++) {
17111 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020017112 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017113 if (nid)
17114 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020017115 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017116 }
17117}
17118
17119
17120static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
17121{
17122 struct alc_spec *spec = codec->spec;
17123 hda_nid_t pin;
17124
17125 pin = spec->autocfg.hp_pins[0];
Sasha Alexandrdef319f2009-06-16 16:00:15 -040017126 if (pin) /* connect to front and use dac 0 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017127 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017128 pin = spec->autocfg.speaker_pins[0];
17129 if (pin)
17130 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017131}
17132
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017133#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
17134
17135static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
17136{
17137 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020017138 struct auto_pin_cfg *cfg = &spec->autocfg;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017139 int i;
17140
Takashi Iwai66ceeb62010-08-30 13:05:52 +020017141 for (i = 0; i < cfg->num_inputs; i++) {
17142 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +020017143 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai30ea0982010-09-16 18:47:56 +020017144 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwaie82c0252009-03-23 15:17:38 +010017145 if (nid != ALC861VD_PIN_CD_NID &&
17146 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017147 snd_hda_codec_write(codec, nid, 0,
17148 AC_VERB_SET_AMP_GAIN_MUTE,
17149 AMP_OUT_MUTE);
17150 }
17151 }
17152}
17153
Takashi Iwaif511b012008-08-15 16:46:42 +020017154#define alc861vd_auto_init_input_src alc882_auto_init_input_src
17155
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017156#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
17157#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
17158
17159/* add playback controls from the parsed DAC table */
Takashi Iwai569ed342011-01-19 10:14:46 +010017160/* Based on ALC880 version. But ALC861VD has separate,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017161 * different NIDs for mute/unmute switch and volume control */
17162static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
17163 const struct auto_pin_cfg *cfg)
17164{
Takashi Iwaiea734962011-01-17 11:29:34 +010017165 static const char * const chname[4] = {
17166 "Front", "Surround", "CLFE", "Side"
17167 };
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010017168 const char *pfx = alc_get_line_out_pfx(cfg, true);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017169 hda_nid_t nid_v, nid_s;
17170 int i, err;
17171
17172 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017173 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017174 continue;
17175 nid_v = alc861vd_idx_to_mixer_vol(
17176 alc880_dac_to_idx(
17177 spec->multiout.dac_nids[i]));
17178 nid_s = alc861vd_idx_to_mixer_switch(
17179 alc880_dac_to_idx(
17180 spec->multiout.dac_nids[i]));
17181
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010017182 if (!pfx && i == 2) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017183 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017184 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
17185 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017186 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
17187 HDA_OUTPUT));
17188 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017189 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017190 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
17191 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017192 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
17193 HDA_OUTPUT));
17194 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017195 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017196 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
17197 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017198 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
17199 HDA_INPUT));
17200 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017201 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017202 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
17203 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017204 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
17205 HDA_INPUT));
17206 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017207 return err;
17208 } else {
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010017209 const char *name = pfx;
17210 if (!name)
17211 name = chname[i];
17212 err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
17213 name, i,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017214 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
17215 HDA_OUTPUT));
17216 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017217 return err;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010017218 err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
17219 name, i,
Kailang Yangbdd148a2007-05-08 15:19:08 +020017220 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017221 HDA_INPUT));
17222 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017223 return err;
17224 }
17225 }
17226 return 0;
17227}
17228
17229/* add playback controls for speaker and HP outputs */
17230/* Based on ALC880 version. But ALC861VD has separate,
17231 * different NIDs for mute/unmute switch and volume control */
17232static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
17233 hda_nid_t pin, const char *pfx)
17234{
17235 hda_nid_t nid_v, nid_s;
17236 int err;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017237
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017238 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017239 return 0;
17240
17241 if (alc880_is_fixed_pin(pin)) {
17242 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
17243 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017244 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017245 spec->multiout.hp_nid = nid_v;
17246 else
17247 spec->multiout.extra_out_nid[0] = nid_v;
17248 /* control HP volume/switch on the output mixer amp */
17249 nid_v = alc861vd_idx_to_mixer_vol(
17250 alc880_fixed_pin_idx(pin));
17251 nid_s = alc861vd_idx_to_mixer_switch(
17252 alc880_fixed_pin_idx(pin));
17253
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017254 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017255 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
17256 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017257 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017258 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017259 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
17260 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017261 return err;
17262 } else if (alc880_is_multi_pin(pin)) {
17263 /* set manual connection */
17264 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017265 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017266 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
17267 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017268 return err;
17269 }
17270 return 0;
17271}
17272
17273/* parse the BIOS configuration and set up the alc_spec
17274 * return 1 if successful, 0 if the proper config is not found,
17275 * or a negative error code
17276 * Based on ALC880 version - had to change it to override
17277 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
17278static int alc861vd_parse_auto_config(struct hda_codec *codec)
17279{
17280 struct alc_spec *spec = codec->spec;
17281 int err;
17282 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
17283
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017284 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
17285 alc861vd_ignore);
17286 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017287 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017288 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017289 return 0; /* can't find valid BIOS pin config */
17290
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017291 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
17292 if (err < 0)
17293 return err;
17294 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
17295 if (err < 0)
17296 return err;
17297 err = alc861vd_auto_create_extra_out(spec,
17298 spec->autocfg.speaker_pins[0],
17299 "Speaker");
17300 if (err < 0)
17301 return err;
17302 err = alc861vd_auto_create_extra_out(spec,
17303 spec->autocfg.hp_pins[0],
17304 "Headphone");
17305 if (err < 0)
17306 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020017307 err = alc861vd_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017308 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017309 return err;
17310
17311 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
17312
Takashi Iwai757899a2010-07-30 10:48:14 +020017313 alc_auto_parse_digital(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017314
Takashi Iwai603c4012008-07-30 15:01:44 +020017315 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010017316 add_mixer(spec, spec->kctls.list);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017317
Takashi Iwaid88897e2008-10-31 15:01:37 +010017318 add_verb(spec, alc861vd_volume_init_verbs);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017319
17320 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020017321 spec->input_mux = &spec->private_imux[0];
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017322
Takashi Iwai776e1842007-08-29 15:07:11 +020017323 err = alc_auto_add_mic_boost(codec);
17324 if (err < 0)
17325 return err;
17326
Kailang Yang6227cdc2010-02-25 08:36:52 +010017327 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020017328
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017329 return 1;
17330}
17331
17332/* additional initialization for auto-configuration model */
17333static void alc861vd_auto_init(struct hda_codec *codec)
17334{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017335 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017336 alc861vd_auto_init_multi_out(codec);
17337 alc861vd_auto_init_hp_out(codec);
17338 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020017339 alc861vd_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020017340 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017341 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020017342 alc_inithook(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017343}
17344
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017345enum {
17346 ALC660VD_FIX_ASUS_GPIO1
17347};
17348
17349/* reset GPIO1 */
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017350static const struct alc_fixup alc861vd_fixups[] = {
17351 [ALC660VD_FIX_ASUS_GPIO1] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010017352 .type = ALC_FIXUP_VERBS,
17353 .v.verbs = (const struct hda_verb[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020017354 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
17355 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
17356 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
17357 { }
17358 }
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017359 },
17360};
17361
17362static struct snd_pci_quirk alc861vd_fixup_tbl[] = {
17363 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
17364 {}
17365};
17366
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017367static int patch_alc861vd(struct hda_codec *codec)
17368{
17369 struct alc_spec *spec;
17370 int err, board_config;
17371
17372 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
17373 if (spec == NULL)
17374 return -ENOMEM;
17375
17376 codec->spec = spec;
17377
17378 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
17379 alc861vd_models,
17380 alc861vd_cfg_tbl);
17381
17382 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020017383 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
17384 codec->chip_name);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017385 board_config = ALC861VD_AUTO;
17386 }
17387
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010017388 if (board_config == ALC861VD_AUTO) {
17389 alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
17390 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
17391 }
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017392
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017393 if (board_config == ALC861VD_AUTO) {
17394 /* automatic parse from the BIOS config */
17395 err = alc861vd_parse_auto_config(codec);
17396 if (err < 0) {
17397 alc_free(codec);
17398 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017399 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017400 printk(KERN_INFO
17401 "hda_codec: Cannot set up configuration "
17402 "from BIOS. Using base mode...\n");
17403 board_config = ALC861VD_3ST;
17404 }
17405 }
17406
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090017407 err = snd_hda_attach_beep_device(codec, 0x23);
17408 if (err < 0) {
17409 alc_free(codec);
17410 return err;
17411 }
17412
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017413 if (board_config != ALC861VD_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020017414 setup_preset(codec, &alc861vd_presets[board_config]);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017415
Kailang Yang2f893282008-05-27 12:14:47 +020017416 if (codec->vendor_id == 0x10ec0660) {
Kailang Yangf9423e72008-05-27 12:32:25 +020017417 /* always turn on EAPD */
Takashi Iwaid88897e2008-10-31 15:01:37 +010017418 add_verb(spec, alc660vd_eapd_verbs);
Kailang Yang2f893282008-05-27 12:14:47 +020017419 }
17420
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017421 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
17422 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
17423
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017424 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
17425 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
17426
Takashi Iwaidd704692009-08-11 08:45:11 +020017427 if (!spec->adc_nids) {
17428 spec->adc_nids = alc861vd_adc_nids;
17429 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
17430 }
17431 if (!spec->capsrc_nids)
17432 spec->capsrc_nids = alc861vd_capsrc_nids;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017433
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017434 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010017435 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017436
Takashi Iwai2134ea42008-01-10 16:53:55 +010017437 spec->vmaster_nid = 0x02;
17438
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010017439 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwai7fa90e82010-04-12 08:49:00 +020017440
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017441 codec->patch_ops = alc_patch_ops;
17442
17443 if (board_config == ALC861VD_AUTO)
17444 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020017445#ifdef CONFIG_SND_HDA_POWER_SAVE
17446 if (!spec->loopback.amplist)
17447 spec->loopback.amplist = alc861vd_loopbacks;
17448#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017449
17450 return 0;
17451}
17452
17453/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017454 * ALC662 support
17455 *
17456 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
17457 * configuration. Each pin widget can choose any input DACs and a mixer.
17458 * Each ADC is connected from a mixer of all inputs. This makes possible
17459 * 6-channel independent captures.
17460 *
17461 * In addition, an independent DAC for the multi-playback (not used in this
17462 * driver yet).
17463 */
17464#define ALC662_DIGOUT_NID 0x06
17465#define ALC662_DIGIN_NID 0x0a
17466
17467static hda_nid_t alc662_dac_nids[4] = {
17468 /* front, rear, clfe, rear_surr */
17469 0x02, 0x03, 0x04
17470};
17471
Kailang Yang622e84c2009-04-21 07:39:04 +020017472static hda_nid_t alc272_dac_nids[2] = {
17473 0x02, 0x03
17474};
17475
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017476static hda_nid_t alc662_adc_nids[2] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017477 /* ADC1-2 */
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017478 0x09, 0x08
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017479};
Takashi Iwaie1406342008-02-11 18:32:32 +010017480
Kailang Yang622e84c2009-04-21 07:39:04 +020017481static hda_nid_t alc272_adc_nids[1] = {
17482 /* ADC1-2 */
17483 0x08,
17484};
17485
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017486static hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 };
Kailang Yang622e84c2009-04-21 07:39:04 +020017487static hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
17488
Takashi Iwaie1406342008-02-11 18:32:32 +010017489
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017490/* input MUX */
17491/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017492static struct hda_input_mux alc662_capture_source = {
17493 .num_items = 4,
17494 .items = {
17495 { "Mic", 0x0 },
17496 { "Front Mic", 0x1 },
17497 { "Line", 0x2 },
17498 { "CD", 0x4 },
17499 },
17500};
17501
17502static struct hda_input_mux alc662_lenovo_101e_capture_source = {
17503 .num_items = 2,
17504 .items = {
17505 { "Mic", 0x1 },
17506 { "Line", 0x2 },
17507 },
17508};
Kailang Yang291702f2007-10-16 14:28:03 +020017509
Kailang Yang6dda9f42008-05-27 12:05:31 +020017510static struct hda_input_mux alc663_capture_source = {
17511 .num_items = 3,
17512 .items = {
17513 { "Mic", 0x0 },
17514 { "Front Mic", 0x1 },
17515 { "Line", 0x2 },
17516 },
17517};
17518
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017519#if 0 /* set to 1 for testing other input sources below */
Chris Pockelé9541ba12009-05-12 08:08:53 +020017520static struct hda_input_mux alc272_nc10_capture_source = {
17521 .num_items = 16,
17522 .items = {
17523 { "Autoselect Mic", 0x0 },
17524 { "Internal Mic", 0x1 },
17525 { "In-0x02", 0x2 },
17526 { "In-0x03", 0x3 },
17527 { "In-0x04", 0x4 },
17528 { "In-0x05", 0x5 },
17529 { "In-0x06", 0x6 },
17530 { "In-0x07", 0x7 },
17531 { "In-0x08", 0x8 },
17532 { "In-0x09", 0x9 },
17533 { "In-0x0a", 0x0a },
17534 { "In-0x0b", 0x0b },
17535 { "In-0x0c", 0x0c },
17536 { "In-0x0d", 0x0d },
17537 { "In-0x0e", 0x0e },
17538 { "In-0x0f", 0x0f },
17539 },
17540};
17541#endif
17542
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017543/*
17544 * 2ch mode
17545 */
17546static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
17547 { 2, NULL }
17548};
17549
17550/*
17551 * 2ch mode
17552 */
17553static struct hda_verb alc662_3ST_ch2_init[] = {
17554 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
17555 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
17556 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
17557 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
17558 { } /* end */
17559};
17560
17561/*
17562 * 6ch mode
17563 */
17564static struct hda_verb alc662_3ST_ch6_init[] = {
17565 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17566 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
17567 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
17568 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17569 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
17570 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
17571 { } /* end */
17572};
17573
17574static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
17575 { 2, alc662_3ST_ch2_init },
17576 { 6, alc662_3ST_ch6_init },
17577};
17578
17579/*
17580 * 2ch mode
17581 */
17582static struct hda_verb alc662_sixstack_ch6_init[] = {
17583 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
17584 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
17585 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17586 { } /* end */
17587};
17588
17589/*
17590 * 6ch mode
17591 */
17592static struct hda_verb alc662_sixstack_ch8_init[] = {
17593 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17594 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17595 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17596 { } /* end */
17597};
17598
17599static struct hda_channel_mode alc662_5stack_modes[2] = {
17600 { 2, alc662_sixstack_ch6_init },
17601 { 6, alc662_sixstack_ch8_init },
17602};
17603
17604/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
17605 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
17606 */
17607
17608static struct snd_kcontrol_new alc662_base_mixer[] = {
17609 /* output mixer control */
17610 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017611 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017612 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017613 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017614 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17615 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017616 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
17617 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017618 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17619
17620 /*Input mixer control */
17621 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
17622 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
17623 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
17624 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
17625 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
17626 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
17627 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
17628 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017629 { } /* end */
17630};
17631
17632static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
17633 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017634 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017635 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17636 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
17637 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
17638 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17639 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17640 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17641 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17642 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17643 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017644 { } /* end */
17645};
17646
17647static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
17648 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017649 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017650 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017651 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017652 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17653 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017654 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
17655 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017656 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17657 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
17658 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
17659 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17660 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17661 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17662 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17663 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17664 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017665 { } /* end */
17666};
17667
17668static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
17669 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17670 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010017671 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17672 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017673 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17674 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17675 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17676 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17677 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017678 { } /* end */
17679};
17680
Kailang Yang291702f2007-10-16 14:28:03 +020017681static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020017682 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17683 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang291702f2007-10-16 14:28:03 +020017684
David Henningsson5f99f862011-01-04 15:24:24 +010017685 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017686 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17687 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020017688
David Henningsson5f99f862011-01-04 15:24:24 +010017689 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017690 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17691 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020017692 { } /* end */
17693};
17694
Kailang Yang8c427222008-01-10 13:03:59 +010017695static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020017696 ALC262_HIPPO_MASTER_SWITCH,
17697 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017698 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017699 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17700 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017701 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
17702 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17703 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17704 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17705 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17706 { } /* end */
17707};
17708
Kailang Yangf1d4e282008-08-26 14:03:29 +020017709static struct hda_bind_ctls alc663_asus_bind_master_vol = {
17710 .ops = &snd_hda_bind_vol,
17711 .values = {
17712 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17713 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
17714 0
17715 },
17716};
17717
17718static struct hda_bind_ctls alc663_asus_one_bind_switch = {
17719 .ops = &snd_hda_bind_sw,
17720 .values = {
17721 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17722 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17723 0
17724 },
17725};
17726
Kailang Yang6dda9f42008-05-27 12:05:31 +020017727static struct snd_kcontrol_new alc663_m51va_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017728 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17729 HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
17730 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17731 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17732 { } /* end */
17733};
17734
17735static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
17736 .ops = &snd_hda_bind_sw,
17737 .values = {
17738 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17739 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17740 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17741 0
17742 },
17743};
17744
17745static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
17746 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17747 HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
17748 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17749 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17750 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17751 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17752
17753 { } /* end */
17754};
17755
17756static struct hda_bind_ctls alc663_asus_four_bind_switch = {
17757 .ops = &snd_hda_bind_sw,
17758 .values = {
17759 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17760 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17761 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17762 0
17763 },
17764};
17765
17766static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
17767 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17768 HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
17769 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17770 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17771 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17772 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17773 { } /* end */
17774};
17775
17776static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017777 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17778 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017779 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17780 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17781 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17782 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17783 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17784 { } /* end */
17785};
17786
17787static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
17788 .ops = &snd_hda_bind_vol,
17789 .values = {
17790 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17791 HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
17792 0
17793 },
17794};
17795
17796static struct hda_bind_ctls alc663_asus_two_bind_switch = {
17797 .ops = &snd_hda_bind_sw,
17798 .values = {
17799 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17800 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
17801 0
17802 },
17803};
17804
17805static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
17806 HDA_BIND_VOL("Master Playback Volume",
17807 &alc663_asus_two_bind_master_vol),
17808 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17809 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017810 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17811 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17812 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017813 { } /* end */
17814};
17815
17816static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
17817 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17818 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17819 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17820 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17821 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17822 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017823 { } /* end */
17824};
17825
17826static struct snd_kcontrol_new alc663_g71v_mixer[] = {
17827 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17828 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17829 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17830 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17831 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17832
17833 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17834 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017835 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17836 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017837 { } /* end */
17838};
17839
17840static struct snd_kcontrol_new alc663_g50v_mixer[] = {
17841 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17842 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17843 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17844
17845 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17846 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017847 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17848 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017849 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17850 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17851 { } /* end */
17852};
17853
Kailang Yangebb83ee2009-12-17 12:23:00 +010017854static struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = {
17855 .ops = &snd_hda_bind_sw,
17856 .values = {
17857 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17858 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17859 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17860 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17861 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17862 0
17863 },
17864};
17865
17866static struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = {
17867 .ops = &snd_hda_bind_sw,
17868 .values = {
17869 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17870 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17871 0
17872 },
17873};
17874
17875static struct snd_kcontrol_new alc663_mode7_mixer[] = {
17876 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17877 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17878 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17879 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17880 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17881 HDA_CODEC_VOLUME("IntMic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17882 HDA_CODEC_MUTE("IntMic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17883 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17884 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17885 { } /* end */
17886};
17887
17888static struct snd_kcontrol_new alc663_mode8_mixer[] = {
17889 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17890 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17891 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17892 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17893 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17894 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17895 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17896 { } /* end */
17897};
17898
17899
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017900static struct snd_kcontrol_new alc662_chmode_mixer[] = {
17901 {
17902 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
17903 .name = "Channel Mode",
17904 .info = alc_ch_mode_info,
17905 .get = alc_ch_mode_get,
17906 .put = alc_ch_mode_put,
17907 },
17908 { } /* end */
17909};
17910
17911static struct hda_verb alc662_init_verbs[] = {
17912 /* ADC: mute amp left and right */
17913 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17914 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017915
Kailang Yangb60dd392007-09-20 12:50:29 +020017916 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17917 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17918 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17919 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17920 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17921 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017922
17923 /* Front Pin: output 0 (0x0c) */
17924 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17925 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17926
17927 /* Rear Pin: output 1 (0x0d) */
17928 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17929 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17930
17931 /* CLFE Pin: output 2 (0x0e) */
17932 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17933 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17934
17935 /* Mic (rear) pin: input vref at 80% */
17936 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17937 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17938 /* Front Mic pin: input vref at 80% */
17939 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17940 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17941 /* Line In pin: input */
17942 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17943 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17944 /* Line-2 In: Headphone output (output 0 - 0x0c) */
17945 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17946 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17947 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
17948 /* CD pin widget for input */
17949 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17950
17951 /* FIXME: use matrix-type input source selection */
17952 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
17953 /* Input mixer */
17954 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang291702f2007-10-16 14:28:03 +020017955 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017956
17957 /* always trun on EAPD */
17958 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
17959 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
17960
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017961 { }
17962};
17963
Kailang Yangcec27c82010-02-04 14:18:18 +010017964static struct hda_verb alc663_init_verbs[] = {
17965 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17966 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17967 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17968 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17969 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17970 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17971 { }
17972};
17973
17974static struct hda_verb alc272_init_verbs[] = {
17975 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17976 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17977 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17978 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17979 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17980 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17981 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17982 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17983 { }
17984};
17985
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017986static struct hda_verb alc662_sue_init_verbs[] = {
17987 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
17988 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020017989 {}
17990};
17991
17992static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
17993 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17994 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17995 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017996};
17997
Kailang Yang8c427222008-01-10 13:03:59 +010017998/* Set Unsolicited Event*/
17999static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
18000 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
18001 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18002 {}
18003};
18004
Kailang Yang6dda9f42008-05-27 12:05:31 +020018005static struct hda_verb alc663_m51va_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020018006 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18007 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yang6dda9f42008-05-27 12:05:31 +020018008 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18009 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf1d4e282008-08-26 14:03:29 +020018010 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18011 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18012 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020018013 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18014 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18015 {}
18016};
18017
Kailang Yangf1d4e282008-08-26 14:03:29 +020018018static struct hda_verb alc663_21jd_amic_init_verbs[] = {
18019 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18020 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18021 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18022 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18023 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
18024 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18025 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18026 {}
18027};
18028
18029static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
18030 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18031 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18032 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18033 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
18034 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18035 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
18036 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18037 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18038 {}
18039};
18040
18041static struct hda_verb alc663_15jd_amic_init_verbs[] = {
18042 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18043 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18044 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18045 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18046 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
18047 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18048 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18049 {}
18050};
18051
18052static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
18053 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18054 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18055 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18056 {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
18057 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18058 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18059 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
18060 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18061 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
18062 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18063 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18064 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18065 {}
18066};
18067
18068static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
18069 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18070 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18071 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18072 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18073 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18074 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18075 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18076 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18077 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
18078 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18079 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18080 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18081 {}
18082};
18083
Kailang Yang6dda9f42008-05-27 12:05:31 +020018084static struct hda_verb alc663_g71v_init_verbs[] = {
18085 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18086 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
18087 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
18088
18089 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18090 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18091 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
18092
18093 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
18094 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
18095 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
18096 {}
18097};
18098
18099static struct hda_verb alc663_g50v_init_verbs[] = {
18100 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18101 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18102 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
18103
18104 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18105 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18106 {}
18107};
18108
Kailang Yangf1d4e282008-08-26 14:03:29 +020018109static struct hda_verb alc662_ecs_init_verbs[] = {
18110 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
18111 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18112 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18113 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18114 {}
18115};
18116
Kailang Yang622e84c2009-04-21 07:39:04 +020018117static struct hda_verb alc272_dell_zm1_init_verbs[] = {
18118 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18119 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18120 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18121 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18122 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18123 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18124 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18125 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18126 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
18127 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18128 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18129 {}
18130};
18131
18132static struct hda_verb alc272_dell_init_verbs[] = {
18133 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18134 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18135 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18136 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18137 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18138 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18139 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18140 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18141 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
18142 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18143 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18144 {}
18145};
18146
Kailang Yangebb83ee2009-12-17 12:23:00 +010018147static struct hda_verb alc663_mode7_init_verbs[] = {
18148 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18149 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18150 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
18151 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18152 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18153 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18154 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
18155 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18156 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18157 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18158 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18159 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
18160 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18161 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18162 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18163 {}
18164};
18165
18166static struct hda_verb alc663_mode8_init_verbs[] = {
18167 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18168 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18169 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18170 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
18171 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18172 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
18173 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18174 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18175 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18176 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18177 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18178 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18179 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
18180 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18181 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18182 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18183 {}
18184};
18185
Kailang Yangf1d4e282008-08-26 14:03:29 +020018186static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
18187 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
18188 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
18189 { } /* end */
18190};
18191
Kailang Yang622e84c2009-04-21 07:39:04 +020018192static struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
18193 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
18194 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
18195 { } /* end */
18196};
18197
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018198static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
18199{
18200 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018201 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018202
Wu Fengguang864f92b2009-11-18 12:38:02 +080018203 present = snd_hda_jack_detect(codec, 0x14);
Takashi Iwai47fd8302007-08-10 17:11:07 +020018204 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080018205
Takashi Iwai47fd8302007-08-10 17:11:07 +020018206 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
18207 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018208}
18209
18210static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
18211{
18212 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018213 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018214
Wu Fengguang864f92b2009-11-18 12:38:02 +080018215 present = snd_hda_jack_detect(codec, 0x1b);
Takashi Iwai47fd8302007-08-10 17:11:07 +020018216 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080018217
Takashi Iwai47fd8302007-08-10 17:11:07 +020018218 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
18219 HDA_AMP_MUTE, bits);
18220 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
18221 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018222}
18223
18224static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
18225 unsigned int res)
18226{
18227 if ((res >> 26) == ALC880_HP_EVENT)
18228 alc662_lenovo_101e_all_automute(codec);
18229 if ((res >> 26) == ALC880_FRONT_EVENT)
18230 alc662_lenovo_101e_ispeaker_automute(codec);
18231}
18232
Kailang Yang291702f2007-10-16 14:28:03 +020018233/* unsolicited event for HP jack sensing */
18234static void alc662_eeepc_unsol_event(struct hda_codec *codec,
18235 unsigned int res)
18236{
Kailang Yang291702f2007-10-16 14:28:03 +020018237 if ((res >> 26) == ALC880_MIC_EVENT)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018238 alc_mic_automute(codec);
Takashi Iwai42171c12009-05-08 14:11:43 +020018239 else
18240 alc262_hippo_unsol_event(codec, res);
Kailang Yang291702f2007-10-16 14:28:03 +020018241}
18242
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018243static void alc662_eeepc_setup(struct hda_codec *codec)
Kailang Yang291702f2007-10-16 14:28:03 +020018244{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018245 struct alc_spec *spec = codec->spec;
18246
18247 alc262_hippo1_setup(codec);
18248 spec->ext_mic.pin = 0x18;
18249 spec->ext_mic.mux_idx = 0;
18250 spec->int_mic.pin = 0x19;
18251 spec->int_mic.mux_idx = 1;
18252 spec->auto_mic = 1;
Kailang Yang291702f2007-10-16 14:28:03 +020018253}
18254
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018255static void alc662_eeepc_inithook(struct hda_codec *codec)
18256{
18257 alc262_hippo_automute(codec);
18258 alc_mic_automute(codec);
18259}
18260
18261static void alc662_eeepc_ep20_setup(struct hda_codec *codec)
Kailang Yang8c427222008-01-10 13:03:59 +010018262{
Takashi Iwai42171c12009-05-08 14:11:43 +020018263 struct alc_spec *spec = codec->spec;
18264
18265 spec->autocfg.hp_pins[0] = 0x14;
18266 spec->autocfg.speaker_pins[0] = 0x1b;
Kailang Yang8c427222008-01-10 13:03:59 +010018267}
18268
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018269#define alc662_eeepc_ep20_inithook alc262_hippo_master_update
18270
Kailang Yang6dda9f42008-05-27 12:05:31 +020018271static void alc663_m51va_speaker_automute(struct hda_codec *codec)
18272{
18273 unsigned int present;
18274 unsigned char bits;
18275
Wu Fengguang864f92b2009-11-18 12:38:02 +080018276 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018277 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yangf1d4e282008-08-26 14:03:29 +020018278 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018279 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018280 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018281 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018282}
18283
18284static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
18285{
18286 unsigned int present;
18287 unsigned char bits;
18288
Wu Fengguang864f92b2009-11-18 12:38:02 +080018289 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018290 bits = present ? HDA_AMP_MUTE : 0;
18291 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018292 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018293 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018294 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018295 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018296 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018297 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018298 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018299}
18300
18301static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
18302{
18303 unsigned int present;
18304 unsigned char bits;
18305
Wu Fengguang864f92b2009-11-18 12:38:02 +080018306 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018307 bits = present ? HDA_AMP_MUTE : 0;
18308 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018309 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018310 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018311 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018312 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018313 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018314 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018315 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018316}
18317
18318static void alc662_f5z_speaker_automute(struct hda_codec *codec)
18319{
18320 unsigned int present;
18321 unsigned char bits;
18322
Wu Fengguang864f92b2009-11-18 12:38:02 +080018323 present = snd_hda_jack_detect(codec, 0x1b);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018324 bits = present ? 0 : PIN_OUT;
18325 snd_hda_codec_write(codec, 0x14, 0,
18326 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
18327}
18328
18329static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
18330{
18331 unsigned int present1, present2;
18332
Wu Fengguang864f92b2009-11-18 12:38:02 +080018333 present1 = snd_hda_jack_detect(codec, 0x21);
18334 present2 = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018335
18336 if (present1 || present2) {
18337 snd_hda_codec_write_cache(codec, 0x14, 0,
18338 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
18339 } else {
18340 snd_hda_codec_write_cache(codec, 0x14, 0,
18341 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
18342 }
18343}
18344
18345static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
18346{
18347 unsigned int present1, present2;
18348
Wu Fengguang864f92b2009-11-18 12:38:02 +080018349 present1 = snd_hda_jack_detect(codec, 0x1b);
18350 present2 = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018351
18352 if (present1 || present2) {
18353 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018354 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018355 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018356 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018357 } else {
18358 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018359 HDA_AMP_MUTE, 0);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018360 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018361 HDA_AMP_MUTE, 0);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018362 }
Kailang Yang6dda9f42008-05-27 12:05:31 +020018363}
18364
Kailang Yangebb83ee2009-12-17 12:23:00 +010018365static void alc663_two_hp_m7_speaker_automute(struct hda_codec *codec)
18366{
18367 unsigned int present1, present2;
18368
18369 present1 = snd_hda_codec_read(codec, 0x1b, 0,
18370 AC_VERB_GET_PIN_SENSE, 0)
18371 & AC_PINSENSE_PRESENCE;
18372 present2 = snd_hda_codec_read(codec, 0x21, 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
18389static void alc663_two_hp_m8_speaker_automute(struct hda_codec *codec)
18390{
18391 unsigned int present1, present2;
18392
18393 present1 = snd_hda_codec_read(codec, 0x21, 0,
18394 AC_VERB_GET_PIN_SENSE, 0)
18395 & AC_PINSENSE_PRESENCE;
18396 present2 = snd_hda_codec_read(codec, 0x15, 0,
18397 AC_VERB_GET_PIN_SENSE, 0)
18398 & AC_PINSENSE_PRESENCE;
18399
18400 if (present1 || present2) {
18401 snd_hda_codec_write_cache(codec, 0x14, 0,
18402 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
18403 snd_hda_codec_write_cache(codec, 0x17, 0,
18404 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
18405 } else {
18406 snd_hda_codec_write_cache(codec, 0x14, 0,
18407 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
18408 snd_hda_codec_write_cache(codec, 0x17, 0,
18409 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
18410 }
18411}
18412
Kailang Yang6dda9f42008-05-27 12:05:31 +020018413static void alc663_m51va_unsol_event(struct hda_codec *codec,
18414 unsigned int res)
18415{
18416 switch (res >> 26) {
18417 case ALC880_HP_EVENT:
18418 alc663_m51va_speaker_automute(codec);
18419 break;
18420 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018421 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018422 break;
18423 }
18424}
18425
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018426static void alc663_m51va_setup(struct hda_codec *codec)
18427{
18428 struct alc_spec *spec = codec->spec;
18429 spec->ext_mic.pin = 0x18;
18430 spec->ext_mic.mux_idx = 0;
18431 spec->int_mic.pin = 0x12;
Kailang Yangebb83ee2009-12-17 12:23:00 +010018432 spec->int_mic.mux_idx = 9;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018433 spec->auto_mic = 1;
18434}
18435
Kailang Yang6dda9f42008-05-27 12:05:31 +020018436static void alc663_m51va_inithook(struct hda_codec *codec)
18437{
18438 alc663_m51va_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018439 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018440}
18441
Kailang Yangf1d4e282008-08-26 14:03:29 +020018442/* ***************** Mode1 ******************************/
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018443#define alc663_mode1_unsol_event alc663_m51va_unsol_event
Kailang Yangebb83ee2009-12-17 12:23:00 +010018444
18445static void alc663_mode1_setup(struct hda_codec *codec)
18446{
18447 struct alc_spec *spec = codec->spec;
18448 spec->ext_mic.pin = 0x18;
18449 spec->ext_mic.mux_idx = 0;
18450 spec->int_mic.pin = 0x19;
18451 spec->int_mic.mux_idx = 1;
18452 spec->auto_mic = 1;
18453}
18454
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018455#define alc663_mode1_inithook alc663_m51va_inithook
Kailang Yangf1d4e282008-08-26 14:03:29 +020018456
Kailang Yangf1d4e282008-08-26 14:03:29 +020018457/* ***************** Mode2 ******************************/
18458static void alc662_mode2_unsol_event(struct hda_codec *codec,
18459 unsigned int res)
18460{
18461 switch (res >> 26) {
18462 case ALC880_HP_EVENT:
18463 alc662_f5z_speaker_automute(codec);
18464 break;
18465 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018466 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018467 break;
18468 }
18469}
18470
Kailang Yangebb83ee2009-12-17 12:23:00 +010018471#define alc662_mode2_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018472
Kailang Yangf1d4e282008-08-26 14:03:29 +020018473static void alc662_mode2_inithook(struct hda_codec *codec)
18474{
18475 alc662_f5z_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018476 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018477}
18478/* ***************** Mode3 ******************************/
18479static void alc663_mode3_unsol_event(struct hda_codec *codec,
18480 unsigned int res)
18481{
18482 switch (res >> 26) {
18483 case ALC880_HP_EVENT:
18484 alc663_two_hp_m1_speaker_automute(codec);
18485 break;
18486 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018487 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018488 break;
18489 }
18490}
18491
Kailang Yangebb83ee2009-12-17 12:23:00 +010018492#define alc663_mode3_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018493
Kailang Yangf1d4e282008-08-26 14:03:29 +020018494static void alc663_mode3_inithook(struct hda_codec *codec)
18495{
18496 alc663_two_hp_m1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018497 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018498}
18499/* ***************** Mode4 ******************************/
18500static void alc663_mode4_unsol_event(struct hda_codec *codec,
18501 unsigned int res)
18502{
18503 switch (res >> 26) {
18504 case ALC880_HP_EVENT:
18505 alc663_21jd_two_speaker_automute(codec);
18506 break;
18507 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018508 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018509 break;
18510 }
18511}
18512
Kailang Yangebb83ee2009-12-17 12:23:00 +010018513#define alc663_mode4_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018514
Kailang Yangf1d4e282008-08-26 14:03:29 +020018515static void alc663_mode4_inithook(struct hda_codec *codec)
18516{
18517 alc663_21jd_two_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018518 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018519}
18520/* ***************** Mode5 ******************************/
18521static void alc663_mode5_unsol_event(struct hda_codec *codec,
18522 unsigned int res)
18523{
18524 switch (res >> 26) {
18525 case ALC880_HP_EVENT:
18526 alc663_15jd_two_speaker_automute(codec);
18527 break;
18528 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018529 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018530 break;
18531 }
18532}
18533
Kailang Yangebb83ee2009-12-17 12:23:00 +010018534#define alc663_mode5_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018535
Kailang Yangf1d4e282008-08-26 14:03:29 +020018536static void alc663_mode5_inithook(struct hda_codec *codec)
18537{
18538 alc663_15jd_two_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018539 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018540}
18541/* ***************** Mode6 ******************************/
18542static void alc663_mode6_unsol_event(struct hda_codec *codec,
18543 unsigned int res)
18544{
18545 switch (res >> 26) {
18546 case ALC880_HP_EVENT:
18547 alc663_two_hp_m2_speaker_automute(codec);
18548 break;
18549 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018550 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018551 break;
18552 }
18553}
18554
Kailang Yangebb83ee2009-12-17 12:23:00 +010018555#define alc663_mode6_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018556
Kailang Yangf1d4e282008-08-26 14:03:29 +020018557static void alc663_mode6_inithook(struct hda_codec *codec)
18558{
18559 alc663_two_hp_m2_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018560 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018561}
18562
Kailang Yangebb83ee2009-12-17 12:23:00 +010018563/* ***************** Mode7 ******************************/
18564static void alc663_mode7_unsol_event(struct hda_codec *codec,
18565 unsigned int res)
18566{
18567 switch (res >> 26) {
18568 case ALC880_HP_EVENT:
18569 alc663_two_hp_m7_speaker_automute(codec);
18570 break;
18571 case ALC880_MIC_EVENT:
18572 alc_mic_automute(codec);
18573 break;
18574 }
18575}
18576
18577#define alc663_mode7_setup alc663_mode1_setup
18578
18579static void alc663_mode7_inithook(struct hda_codec *codec)
18580{
18581 alc663_two_hp_m7_speaker_automute(codec);
18582 alc_mic_automute(codec);
18583}
18584
18585/* ***************** Mode8 ******************************/
18586static void alc663_mode8_unsol_event(struct hda_codec *codec,
18587 unsigned int res)
18588{
18589 switch (res >> 26) {
18590 case ALC880_HP_EVENT:
18591 alc663_two_hp_m8_speaker_automute(codec);
18592 break;
18593 case ALC880_MIC_EVENT:
18594 alc_mic_automute(codec);
18595 break;
18596 }
18597}
18598
18599#define alc663_mode8_setup alc663_m51va_setup
18600
18601static void alc663_mode8_inithook(struct hda_codec *codec)
18602{
18603 alc663_two_hp_m8_speaker_automute(codec);
18604 alc_mic_automute(codec);
18605}
18606
Kailang Yang6dda9f42008-05-27 12:05:31 +020018607static void alc663_g71v_hp_automute(struct hda_codec *codec)
18608{
18609 unsigned int present;
18610 unsigned char bits;
18611
Wu Fengguang864f92b2009-11-18 12:38:02 +080018612 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018613 bits = present ? HDA_AMP_MUTE : 0;
18614 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
18615 HDA_AMP_MUTE, bits);
18616 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
18617 HDA_AMP_MUTE, bits);
18618}
18619
18620static void alc663_g71v_front_automute(struct hda_codec *codec)
18621{
18622 unsigned int present;
18623 unsigned char bits;
18624
Wu Fengguang864f92b2009-11-18 12:38:02 +080018625 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018626 bits = present ? HDA_AMP_MUTE : 0;
18627 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
18628 HDA_AMP_MUTE, bits);
18629}
18630
18631static void alc663_g71v_unsol_event(struct hda_codec *codec,
18632 unsigned int res)
18633{
18634 switch (res >> 26) {
18635 case ALC880_HP_EVENT:
18636 alc663_g71v_hp_automute(codec);
18637 break;
18638 case ALC880_FRONT_EVENT:
18639 alc663_g71v_front_automute(codec);
18640 break;
18641 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018642 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018643 break;
18644 }
18645}
18646
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018647#define alc663_g71v_setup alc663_m51va_setup
18648
Kailang Yang6dda9f42008-05-27 12:05:31 +020018649static void alc663_g71v_inithook(struct hda_codec *codec)
18650{
18651 alc663_g71v_front_automute(codec);
18652 alc663_g71v_hp_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018653 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018654}
18655
18656static void alc663_g50v_unsol_event(struct hda_codec *codec,
18657 unsigned int res)
18658{
18659 switch (res >> 26) {
18660 case ALC880_HP_EVENT:
18661 alc663_m51va_speaker_automute(codec);
18662 break;
18663 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018664 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018665 break;
18666 }
18667}
18668
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018669#define alc663_g50v_setup alc663_m51va_setup
18670
Kailang Yang6dda9f42008-05-27 12:05:31 +020018671static void alc663_g50v_inithook(struct hda_codec *codec)
18672{
18673 alc663_m51va_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018674 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018675}
18676
Kailang Yangf1d4e282008-08-26 14:03:29 +020018677static struct snd_kcontrol_new alc662_ecs_mixer[] = {
18678 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020018679 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018680
David Henningsson5f99f862011-01-04 15:24:24 +010018681 HDA_CODEC_VOLUME("Mic/LineIn Boost Volume", 0x18, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010018682 HDA_CODEC_VOLUME("Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
18683 HDA_CODEC_MUTE("Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020018684
David Henningsson5f99f862011-01-04 15:24:24 +010018685 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010018686 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
18687 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020018688 { } /* end */
18689};
18690
Chris Pockelé9541ba12009-05-12 08:08:53 +020018691static struct snd_kcontrol_new alc272_nc10_mixer[] = {
18692 /* Master Playback automatically created from Speaker and Headphone */
18693 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
18694 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
18695 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
18696 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
18697
David Henningsson8607f7c2010-12-20 14:43:54 +010018698 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
18699 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010018700 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Chris Pockelé9541ba12009-05-12 08:08:53 +020018701
David Henningsson28c4edb2010-12-20 14:24:29 +010018702 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
18703 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010018704 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Chris Pockelé9541ba12009-05-12 08:08:53 +020018705 { } /* end */
18706};
18707
Takashi Iwaicb53c622007-08-10 17:21:45 +020018708#ifdef CONFIG_SND_HDA_POWER_SAVE
18709#define alc662_loopbacks alc880_loopbacks
18710#endif
18711
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018712
Sasha Alexandrdef319f2009-06-16 16:00:15 -040018713/* pcm configuration: identical with ALC880 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018714#define alc662_pcm_analog_playback alc880_pcm_analog_playback
18715#define alc662_pcm_analog_capture alc880_pcm_analog_capture
18716#define alc662_pcm_digital_playback alc880_pcm_digital_playback
18717#define alc662_pcm_digital_capture alc880_pcm_digital_capture
18718
18719/*
18720 * configuration and preset
18721 */
Takashi Iwaiea734962011-01-17 11:29:34 +010018722static const char * const alc662_models[ALC662_MODEL_LAST] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018723 [ALC662_3ST_2ch_DIG] = "3stack-dig",
18724 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
18725 [ALC662_3ST_6ch] = "3stack-6ch",
18726 [ALC662_5ST_DIG] = "6stack-dig",
18727 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020018728 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010018729 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangf1d4e282008-08-26 14:03:29 +020018730 [ALC662_ECS] = "ecs",
Kailang Yang6dda9f42008-05-27 12:05:31 +020018731 [ALC663_ASUS_M51VA] = "m51va",
18732 [ALC663_ASUS_G71V] = "g71v",
18733 [ALC663_ASUS_H13] = "h13",
18734 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangf1d4e282008-08-26 14:03:29 +020018735 [ALC663_ASUS_MODE1] = "asus-mode1",
18736 [ALC662_ASUS_MODE2] = "asus-mode2",
18737 [ALC663_ASUS_MODE3] = "asus-mode3",
18738 [ALC663_ASUS_MODE4] = "asus-mode4",
18739 [ALC663_ASUS_MODE5] = "asus-mode5",
18740 [ALC663_ASUS_MODE6] = "asus-mode6",
Kailang Yangebb83ee2009-12-17 12:23:00 +010018741 [ALC663_ASUS_MODE7] = "asus-mode7",
18742 [ALC663_ASUS_MODE8] = "asus-mode8",
Takashi Iwai01f2bd42009-05-11 08:12:43 +020018743 [ALC272_DELL] = "dell",
18744 [ALC272_DELL_ZM1] = "dell-zm1",
Chris Pockelé9541ba12009-05-12 08:08:53 +020018745 [ALC272_SAMSUNG_NC10] = "samsung-nc10",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018746 [ALC662_AUTO] = "auto",
18747};
18748
18749static struct snd_pci_quirk alc662_cfg_tbl[] = {
Takashi Iwaidea0a502009-02-09 17:14:52 +010018750 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
Kailang Yang622e84c2009-04-21 07:39:04 +020018751 SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
18752 SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018753 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
18754 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
Kailang Yangcec27c82010-02-04 14:18:18 +010018755 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018756 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
18757 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
18758 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
18759 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018760 SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC663_ASUS_MODE1),
18761 SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018762 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018763 SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC663_ASUS_MODE7),
18764 SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC663_ASUS_MODE7),
18765 SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC663_ASUS_MODE8),
18766 SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC663_ASUS_MODE3),
18767 SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018768 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018769 SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_ASUS_MODE2),
18770 SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018771 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
18772 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
18773 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
18774 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018775 SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020018776 SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3),
18777 SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA),
18778 SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018779 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
18780 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
18781 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
18782 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018783 SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018784 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
18785 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang6dda9f42008-05-27 12:05:31 +020018786 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018787 /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/
18788 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
18789 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020018790 SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1),
Kailang Yangcec27c82010-02-04 14:18:18 +010018791 SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020018792 SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1),
18793 SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018794 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
18795 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
18796 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018797 SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018798 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
18799 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020018800 SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018801 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
Kailang Yang80ffe862008-10-15 11:23:27 +020018802 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018803 /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/
18804 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
18805 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018806 SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018807 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
18808 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010018809 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020018810 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010018811 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018812 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
Herton Ronaldo Krzesinski95fe5f22008-09-26 23:48:45 -030018813 SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
18814 ALC662_3ST_6ch_DIG),
Takashi Iwai4dee8ba2010-01-13 17:20:08 +010018815 SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO),
Chris Pockelé9541ba12009-05-12 08:08:53 +020018816 SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
Herton Ronaldo Krzesinskicb559742008-09-26 23:47:45 -030018817 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
18818 ALC662_3ST_6ch_DIG),
Kailang Yang6227cdc2010-02-25 08:36:52 +010018819 SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13),
Vedran Miletic19c009a2008-09-29 20:29:25 +020018820 SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
Takashi Iwai5bd37292009-04-21 18:36:30 +020018821 SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018822 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Takashi Iwai238713d2008-10-05 10:57:39 +020018823 SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
Vedran Miletic19c009a2008-09-29 20:29:25 +020018824 ALC662_3ST_6ch_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018825 SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
18826 ALC663_ASUS_H13),
Anisse Astier965b76d2011-02-10 13:14:44 +010018827 SND_PCI_QUIRK(0x1991, 0x5628, "Ordissimo EVE", ALC662_LENOVO_101E),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018828 {}
18829};
18830
18831static struct alc_config_preset alc662_presets[] = {
18832 [ALC662_3ST_2ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018833 .mixers = { alc662_3ST_2ch_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018834 .init_verbs = { alc662_init_verbs },
18835 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18836 .dac_nids = alc662_dac_nids,
18837 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018838 .dig_in_nid = ALC662_DIGIN_NID,
18839 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18840 .channel_mode = alc662_3ST_2ch_modes,
18841 .input_mux = &alc662_capture_source,
18842 },
18843 [ALC662_3ST_6ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018844 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018845 .init_verbs = { alc662_init_verbs },
18846 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18847 .dac_nids = alc662_dac_nids,
18848 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018849 .dig_in_nid = ALC662_DIGIN_NID,
18850 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18851 .channel_mode = alc662_3ST_6ch_modes,
18852 .need_dac_fix = 1,
18853 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018854 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018855 [ALC662_3ST_6ch] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018856 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018857 .init_verbs = { alc662_init_verbs },
18858 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18859 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018860 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18861 .channel_mode = alc662_3ST_6ch_modes,
18862 .need_dac_fix = 1,
18863 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018864 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018865 [ALC662_5ST_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018866 .mixers = { alc662_base_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018867 .init_verbs = { alc662_init_verbs },
18868 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18869 .dac_nids = alc662_dac_nids,
18870 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018871 .dig_in_nid = ALC662_DIGIN_NID,
18872 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
18873 .channel_mode = alc662_5stack_modes,
18874 .input_mux = &alc662_capture_source,
18875 },
18876 [ALC662_LENOVO_101E] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018877 .mixers = { alc662_lenovo_101e_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018878 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
18879 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18880 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018881 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18882 .channel_mode = alc662_3ST_2ch_modes,
18883 .input_mux = &alc662_lenovo_101e_capture_source,
18884 .unsol_event = alc662_lenovo_101e_unsol_event,
18885 .init_hook = alc662_lenovo_101e_all_automute,
18886 },
Kailang Yang291702f2007-10-16 14:28:03 +020018887 [ALC662_ASUS_EEEPC_P701] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018888 .mixers = { alc662_eeepc_p701_mixer },
Kailang Yang291702f2007-10-16 14:28:03 +020018889 .init_verbs = { alc662_init_verbs,
18890 alc662_eeepc_sue_init_verbs },
18891 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18892 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020018893 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18894 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang291702f2007-10-16 14:28:03 +020018895 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018896 .setup = alc662_eeepc_setup,
Kailang Yang291702f2007-10-16 14:28:03 +020018897 .init_hook = alc662_eeepc_inithook,
18898 },
Kailang Yang8c427222008-01-10 13:03:59 +010018899 [ALC662_ASUS_EEEPC_EP20] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018900 .mixers = { alc662_eeepc_ep20_mixer,
Kailang Yang8c427222008-01-10 13:03:59 +010018901 alc662_chmode_mixer },
18902 .init_verbs = { alc662_init_verbs,
18903 alc662_eeepc_ep20_sue_init_verbs },
18904 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18905 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010018906 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18907 .channel_mode = alc662_3ST_6ch_modes,
18908 .input_mux = &alc662_lenovo_101e_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020018909 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018910 .setup = alc662_eeepc_ep20_setup,
Kailang Yang8c427222008-01-10 13:03:59 +010018911 .init_hook = alc662_eeepc_ep20_inithook,
18912 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018913 [ALC662_ECS] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018914 .mixers = { alc662_ecs_mixer },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018915 .init_verbs = { alc662_init_verbs,
18916 alc662_ecs_init_verbs },
18917 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18918 .dac_nids = alc662_dac_nids,
18919 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18920 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018921 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018922 .setup = alc662_eeepc_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018923 .init_hook = alc662_eeepc_inithook,
18924 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018925 [ALC663_ASUS_M51VA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018926 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018927 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
18928 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18929 .dac_nids = alc662_dac_nids,
18930 .dig_out_nid = ALC662_DIGOUT_NID,
18931 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18932 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018933 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018934 .setup = alc663_m51va_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018935 .init_hook = alc663_m51va_inithook,
18936 },
18937 [ALC663_ASUS_G71V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018938 .mixers = { alc663_g71v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018939 .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
18940 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18941 .dac_nids = alc662_dac_nids,
18942 .dig_out_nid = ALC662_DIGOUT_NID,
18943 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18944 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018945 .unsol_event = alc663_g71v_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018946 .setup = alc663_g71v_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018947 .init_hook = alc663_g71v_inithook,
18948 },
18949 [ALC663_ASUS_H13] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018950 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018951 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
18952 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18953 .dac_nids = alc662_dac_nids,
18954 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18955 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018956 .unsol_event = alc663_m51va_unsol_event,
18957 .init_hook = alc663_m51va_inithook,
18958 },
18959 [ALC663_ASUS_G50V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018960 .mixers = { alc663_g50v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018961 .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
18962 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18963 .dac_nids = alc662_dac_nids,
18964 .dig_out_nid = ALC662_DIGOUT_NID,
18965 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18966 .channel_mode = alc662_3ST_6ch_modes,
18967 .input_mux = &alc663_capture_source,
18968 .unsol_event = alc663_g50v_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018969 .setup = alc663_g50v_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018970 .init_hook = alc663_g50v_inithook,
18971 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018972 [ALC663_ASUS_MODE1] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018973 .mixers = { alc663_m51va_mixer },
18974 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018975 .init_verbs = { alc662_init_verbs,
18976 alc663_21jd_amic_init_verbs },
18977 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18978 .hp_nid = 0x03,
18979 .dac_nids = alc662_dac_nids,
18980 .dig_out_nid = ALC662_DIGOUT_NID,
18981 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18982 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018983 .unsol_event = alc663_mode1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018984 .setup = alc663_mode1_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018985 .init_hook = alc663_mode1_inithook,
18986 },
18987 [ALC662_ASUS_MODE2] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018988 .mixers = { alc662_1bjd_mixer },
18989 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018990 .init_verbs = { alc662_init_verbs,
18991 alc662_1bjd_amic_init_verbs },
18992 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18993 .dac_nids = alc662_dac_nids,
18994 .dig_out_nid = ALC662_DIGOUT_NID,
18995 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18996 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018997 .unsol_event = alc662_mode2_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018998 .setup = alc662_mode2_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018999 .init_hook = alc662_mode2_inithook,
19000 },
19001 [ALC663_ASUS_MODE3] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010019002 .mixers = { alc663_two_hp_m1_mixer },
19003 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020019004 .init_verbs = { alc662_init_verbs,
19005 alc663_two_hp_amic_m1_init_verbs },
19006 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
19007 .hp_nid = 0x03,
19008 .dac_nids = alc662_dac_nids,
19009 .dig_out_nid = ALC662_DIGOUT_NID,
19010 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
19011 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020019012 .unsol_event = alc663_mode3_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020019013 .setup = alc663_mode3_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020019014 .init_hook = alc663_mode3_inithook,
19015 },
19016 [ALC663_ASUS_MODE4] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010019017 .mixers = { alc663_asus_21jd_clfe_mixer },
19018 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020019019 .init_verbs = { alc662_init_verbs,
19020 alc663_21jd_amic_init_verbs},
19021 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
19022 .hp_nid = 0x03,
19023 .dac_nids = alc662_dac_nids,
19024 .dig_out_nid = ALC662_DIGOUT_NID,
19025 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
19026 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020019027 .unsol_event = alc663_mode4_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020019028 .setup = alc663_mode4_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020019029 .init_hook = alc663_mode4_inithook,
19030 },
19031 [ALC663_ASUS_MODE5] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010019032 .mixers = { alc663_asus_15jd_clfe_mixer },
19033 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020019034 .init_verbs = { alc662_init_verbs,
19035 alc663_15jd_amic_init_verbs },
19036 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
19037 .hp_nid = 0x03,
19038 .dac_nids = alc662_dac_nids,
19039 .dig_out_nid = ALC662_DIGOUT_NID,
19040 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
19041 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020019042 .unsol_event = alc663_mode5_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020019043 .setup = alc663_mode5_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020019044 .init_hook = alc663_mode5_inithook,
19045 },
19046 [ALC663_ASUS_MODE6] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010019047 .mixers = { alc663_two_hp_m2_mixer },
19048 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020019049 .init_verbs = { alc662_init_verbs,
19050 alc663_two_hp_amic_m2_init_verbs },
19051 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
19052 .hp_nid = 0x03,
19053 .dac_nids = alc662_dac_nids,
19054 .dig_out_nid = ALC662_DIGOUT_NID,
19055 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
19056 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020019057 .unsol_event = alc663_mode6_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020019058 .setup = alc663_mode6_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020019059 .init_hook = alc663_mode6_inithook,
19060 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010019061 [ALC663_ASUS_MODE7] = {
19062 .mixers = { alc663_mode7_mixer },
19063 .cap_mixer = alc662_auto_capture_mixer,
19064 .init_verbs = { alc662_init_verbs,
19065 alc663_mode7_init_verbs },
19066 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
19067 .hp_nid = 0x03,
19068 .dac_nids = alc662_dac_nids,
19069 .dig_out_nid = ALC662_DIGOUT_NID,
19070 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
19071 .channel_mode = alc662_3ST_2ch_modes,
19072 .unsol_event = alc663_mode7_unsol_event,
19073 .setup = alc663_mode7_setup,
19074 .init_hook = alc663_mode7_inithook,
19075 },
19076 [ALC663_ASUS_MODE8] = {
19077 .mixers = { alc663_mode8_mixer },
19078 .cap_mixer = alc662_auto_capture_mixer,
19079 .init_verbs = { alc662_init_verbs,
19080 alc663_mode8_init_verbs },
19081 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
19082 .hp_nid = 0x03,
19083 .dac_nids = alc662_dac_nids,
19084 .dig_out_nid = ALC662_DIGOUT_NID,
19085 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
19086 .channel_mode = alc662_3ST_2ch_modes,
19087 .unsol_event = alc663_mode8_unsol_event,
19088 .setup = alc663_mode8_setup,
19089 .init_hook = alc663_mode8_inithook,
19090 },
Kailang Yang622e84c2009-04-21 07:39:04 +020019091 [ALC272_DELL] = {
19092 .mixers = { alc663_m51va_mixer },
19093 .cap_mixer = alc272_auto_capture_mixer,
19094 .init_verbs = { alc662_init_verbs, alc272_dell_init_verbs },
19095 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
19096 .dac_nids = alc662_dac_nids,
19097 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
19098 .adc_nids = alc272_adc_nids,
19099 .num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
19100 .capsrc_nids = alc272_capsrc_nids,
19101 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang622e84c2009-04-21 07:39:04 +020019102 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020019103 .setup = alc663_m51va_setup,
Kailang Yang622e84c2009-04-21 07:39:04 +020019104 .init_hook = alc663_m51va_inithook,
19105 },
19106 [ALC272_DELL_ZM1] = {
19107 .mixers = { alc663_m51va_mixer },
19108 .cap_mixer = alc662_auto_capture_mixer,
19109 .init_verbs = { alc662_init_verbs, alc272_dell_zm1_init_verbs },
19110 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
19111 .dac_nids = alc662_dac_nids,
19112 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
19113 .adc_nids = alc662_adc_nids,
Takashi Iwaib59bdf32009-08-11 09:47:30 +020019114 .num_adc_nids = 1,
Kailang Yang622e84c2009-04-21 07:39:04 +020019115 .capsrc_nids = alc662_capsrc_nids,
19116 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang622e84c2009-04-21 07:39:04 +020019117 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020019118 .setup = alc663_m51va_setup,
Kailang Yang622e84c2009-04-21 07:39:04 +020019119 .init_hook = alc663_m51va_inithook,
19120 },
Chris Pockelé9541ba12009-05-12 08:08:53 +020019121 [ALC272_SAMSUNG_NC10] = {
19122 .mixers = { alc272_nc10_mixer },
19123 .init_verbs = { alc662_init_verbs,
19124 alc663_21jd_amic_init_verbs },
19125 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
19126 .dac_nids = alc272_dac_nids,
19127 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
19128 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020019129 /*.input_mux = &alc272_nc10_capture_source,*/
Chris Pockelé9541ba12009-05-12 08:08:53 +020019130 .unsol_event = alc663_mode4_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020019131 .setup = alc663_mode4_setup,
Chris Pockelé9541ba12009-05-12 08:08:53 +020019132 .init_hook = alc663_mode4_inithook,
19133 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019134};
19135
19136
19137/*
19138 * BIOS auto configuration
19139 */
19140
Takashi Iwai7085ec12009-10-02 09:03:58 +020019141/* convert from MIX nid to DAC */
19142static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid)
19143{
19144 if (nid == 0x0f)
19145 return 0x02;
19146 else if (nid >= 0x0c && nid <= 0x0e)
19147 return nid - 0x0c + 0x02;
David Henningssoncc1c4522010-11-24 14:17:47 +010019148 else if (nid == 0x26) /* ALC887-VD has this DAC too */
19149 return 0x25;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019150 else
19151 return 0;
19152}
19153
19154/* get MIX nid connected to the given pin targeted to DAC */
19155static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
19156 hda_nid_t dac)
19157{
David Henningssoncc1c4522010-11-24 14:17:47 +010019158 hda_nid_t mix[5];
Takashi Iwai7085ec12009-10-02 09:03:58 +020019159 int i, num;
19160
19161 num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
19162 for (i = 0; i < num; i++) {
19163 if (alc662_mix_to_dac(mix[i]) == dac)
19164 return mix[i];
19165 }
19166 return 0;
19167}
19168
19169/* look for an empty DAC slot */
19170static hda_nid_t alc662_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
19171{
19172 struct alc_spec *spec = codec->spec;
19173 hda_nid_t srcs[5];
19174 int i, j, num;
19175
19176 num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
19177 if (num < 0)
19178 return 0;
19179 for (i = 0; i < num; i++) {
19180 hda_nid_t nid = alc662_mix_to_dac(srcs[i]);
19181 if (!nid)
19182 continue;
19183 for (j = 0; j < spec->multiout.num_dacs; j++)
19184 if (spec->multiout.dac_nids[j] == nid)
19185 break;
19186 if (j >= spec->multiout.num_dacs)
19187 return nid;
19188 }
19189 return 0;
19190}
19191
19192/* fill in the dac_nids table from the parsed pin configuration */
19193static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
19194 const struct auto_pin_cfg *cfg)
19195{
19196 struct alc_spec *spec = codec->spec;
19197 int i;
19198 hda_nid_t dac;
19199
19200 spec->multiout.dac_nids = spec->private_dac_nids;
19201 for (i = 0; i < cfg->line_outs; i++) {
19202 dac = alc662_look_for_dac(codec, cfg->line_out_pins[i]);
19203 if (!dac)
19204 continue;
19205 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
19206 }
19207 return 0;
19208}
19209
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019210static inline int __alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
19211 hda_nid_t nid, int idx, unsigned int chs)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019212{
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019213 return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019214 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
19215}
19216
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019217static inline int __alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
19218 hda_nid_t nid, int idx, unsigned int chs)
Takashi Iwai7085ec12009-10-02 09:03:58 +020019219{
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019220 return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019221 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
19222}
19223
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019224#define alc662_add_vol_ctl(spec, pfx, nid, chs) \
19225 __alc662_add_vol_ctl(spec, pfx, nid, 0, chs)
19226#define alc662_add_sw_ctl(spec, pfx, nid, chs) \
19227 __alc662_add_sw_ctl(spec, pfx, nid, 0, chs)
Takashi Iwai7085ec12009-10-02 09:03:58 +020019228#define alc662_add_stereo_vol(spec, pfx, nid) \
19229 alc662_add_vol_ctl(spec, pfx, nid, 3)
19230#define alc662_add_stereo_sw(spec, pfx, nid) \
19231 alc662_add_sw_ctl(spec, pfx, nid, 3)
19232
19233/* add playback controls from the parsed DAC table */
19234static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
19235 const struct auto_pin_cfg *cfg)
19236{
19237 struct alc_spec *spec = codec->spec;
Takashi Iwaiea734962011-01-17 11:29:34 +010019238 static const char * const chname[4] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019239 "Front", "Surround", NULL /*CLFE*/, "Side"
19240 };
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019241 const char *pfx = alc_get_line_out_pfx(cfg, true);
Takashi Iwai7085ec12009-10-02 09:03:58 +020019242 hda_nid_t nid, mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019243 int i, err;
19244
19245 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020019246 nid = spec->multiout.dac_nids[i];
19247 if (!nid)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019248 continue;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019249 mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid);
19250 if (!mix)
19251 continue;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019252 if (!pfx && i == 2) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019253 /* Center/LFE */
Takashi Iwai7085ec12009-10-02 09:03:58 +020019254 err = alc662_add_vol_ctl(spec, "Center", nid, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019255 if (err < 0)
19256 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019257 err = alc662_add_vol_ctl(spec, "LFE", nid, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019258 if (err < 0)
19259 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019260 err = alc662_add_sw_ctl(spec, "Center", mix, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019261 if (err < 0)
19262 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019263 err = alc662_add_sw_ctl(spec, "LFE", mix, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019264 if (err < 0)
19265 return err;
19266 } else {
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019267 const char *name = pfx;
19268 if (!name)
19269 name = chname[i];
19270 err = __alc662_add_vol_ctl(spec, name, nid, i, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019271 if (err < 0)
19272 return err;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019273 err = __alc662_add_sw_ctl(spec, name, mix, i, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019274 if (err < 0)
19275 return err;
19276 }
19277 }
19278 return 0;
19279}
19280
19281/* add playback controls for speaker and HP outputs */
Takashi Iwai7085ec12009-10-02 09:03:58 +020019282/* return DAC nid if any new DAC is assigned */
19283static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019284 const char *pfx)
19285{
Takashi Iwai7085ec12009-10-02 09:03:58 +020019286 struct alc_spec *spec = codec->spec;
19287 hda_nid_t nid, mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019288 int err;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019289
19290 if (!pin)
19291 return 0;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019292 nid = alc662_look_for_dac(codec, pin);
19293 if (!nid) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020019294 /* the corresponding DAC is already occupied */
19295 if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
19296 return 0; /* no way */
19297 /* create a switch only */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020019298 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019299 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
19300 }
19301
19302 mix = alc662_dac_to_mix(codec, pin, nid);
19303 if (!mix)
19304 return 0;
19305 err = alc662_add_vol_ctl(spec, pfx, nid, 3);
19306 if (err < 0)
Takashi Iwai24fb9172008-09-02 14:48:20 +020019307 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019308 err = alc662_add_sw_ctl(spec, pfx, mix, 3);
19309 if (err < 0)
19310 return err;
19311 return nid;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019312}
19313
19314/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020019315#define alc662_auto_create_input_ctls \
Takashi Iwai4b7348a2009-10-14 18:25:23 +020019316 alc882_auto_create_input_ctls
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019317
19318static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
19319 hda_nid_t nid, int pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019320 hda_nid_t dac)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019321{
Takashi Iwai7085ec12009-10-02 09:03:58 +020019322 int i, num;
Takashi Iwaice503f32010-07-30 10:37:29 +020019323 hda_nid_t srcs[HDA_MAX_CONNECTIONS];
Takashi Iwai7085ec12009-10-02 09:03:58 +020019324
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019325 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019326 /* need the manual connection? */
Takashi Iwai7085ec12009-10-02 09:03:58 +020019327 num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
19328 if (num <= 1)
19329 return;
19330 for (i = 0; i < num; i++) {
19331 if (alc662_mix_to_dac(srcs[i]) != dac)
19332 continue;
19333 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
19334 return;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019335 }
19336}
19337
19338static void alc662_auto_init_multi_out(struct hda_codec *codec)
19339{
19340 struct alc_spec *spec = codec->spec;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019341 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019342 int i;
19343
19344 for (i = 0; i <= HDA_SIDE; i++) {
19345 hda_nid_t nid = spec->autocfg.line_out_pins[i];
19346 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020019347 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019348 spec->multiout.dac_nids[i]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019349 }
19350}
19351
19352static void alc662_auto_init_hp_out(struct hda_codec *codec)
19353{
19354 struct alc_spec *spec = codec->spec;
19355 hda_nid_t pin;
19356
19357 pin = spec->autocfg.hp_pins[0];
Takashi Iwai7085ec12009-10-02 09:03:58 +020019358 if (pin)
19359 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP,
19360 spec->multiout.hp_nid);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019361 pin = spec->autocfg.speaker_pins[0];
19362 if (pin)
Takashi Iwai7085ec12009-10-02 09:03:58 +020019363 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT,
19364 spec->multiout.extra_out_nid[0]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019365}
19366
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019367#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
19368
19369static void alc662_auto_init_analog_input(struct hda_codec *codec)
19370{
19371 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019372 struct auto_pin_cfg *cfg = &spec->autocfg;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019373 int i;
19374
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019375 for (i = 0; i < cfg->num_inputs; i++) {
19376 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +020019377 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai30ea0982010-09-16 18:47:56 +020019378 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwai52ca15b2009-03-23 12:51:55 +010019379 if (nid != ALC662_PIN_CD_NID &&
Takashi Iwaie82c0252009-03-23 15:17:38 +010019380 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019381 snd_hda_codec_write(codec, nid, 0,
19382 AC_VERB_SET_AMP_GAIN_MUTE,
19383 AMP_OUT_MUTE);
19384 }
19385 }
19386}
19387
Takashi Iwaif511b012008-08-15 16:46:42 +020019388#define alc662_auto_init_input_src alc882_auto_init_input_src
19389
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019390static int alc662_parse_auto_config(struct hda_codec *codec)
19391{
19392 struct alc_spec *spec = codec->spec;
19393 int err;
19394 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
19395
19396 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
19397 alc662_ignore);
19398 if (err < 0)
19399 return err;
19400 if (!spec->autocfg.line_outs)
19401 return 0; /* can't find valid BIOS pin config */
19402
Takashi Iwai7085ec12009-10-02 09:03:58 +020019403 err = alc662_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019404 if (err < 0)
19405 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019406 err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019407 if (err < 0)
19408 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019409 err = alc662_auto_create_extra_out(codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019410 spec->autocfg.speaker_pins[0],
19411 "Speaker");
19412 if (err < 0)
19413 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019414 if (err)
19415 spec->multiout.extra_out_nid[0] = err;
19416 err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019417 "Headphone");
19418 if (err < 0)
19419 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019420 if (err)
19421 spec->multiout.hp_nid = err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020019422 err = alc662_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019423 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019424 return err;
19425
19426 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
19427
Takashi Iwai757899a2010-07-30 10:48:14 +020019428 alc_auto_parse_digital(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019429
Takashi Iwai603c4012008-07-30 15:01:44 +020019430 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010019431 add_mixer(spec, spec->kctls.list);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019432
19433 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020019434 spec->input_mux = &spec->private_imux[0];
Kailang Yangea1fb292008-08-26 12:58:38 +020019435
Kailang Yangcec27c82010-02-04 14:18:18 +010019436 add_verb(spec, alc662_init_verbs);
19437 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019438 codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
Kailang Yangcec27c82010-02-04 14:18:18 +010019439 add_verb(spec, alc663_init_verbs);
19440
19441 if (codec->vendor_id == 0x10ec0272)
19442 add_verb(spec, alc272_init_verbs);
Takashi Iwaiee979a142008-09-02 15:42:20 +020019443
19444 err = alc_auto_add_mic_boost(codec);
19445 if (err < 0)
19446 return err;
19447
Kailang Yang6227cdc2010-02-25 08:36:52 +010019448 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
19449 codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
19450 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0x21);
19451 else
19452 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020019453
Takashi Iwai8c87286f2007-06-19 12:11:16 +020019454 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019455}
19456
19457/* additional initialization for auto-configuration model */
19458static void alc662_auto_init(struct hda_codec *codec)
19459{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019460 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019461 alc662_auto_init_multi_out(codec);
19462 alc662_auto_init_hp_out(codec);
19463 alc662_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020019464 alc662_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020019465 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019466 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020019467 alc_inithook(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019468}
19469
Todd Broch6be79482010-12-07 16:51:05 -080019470static void alc272_fixup_mario(struct hda_codec *codec,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019471 const struct alc_fixup *fix, int action)
Takashi Iwai6fc398c2011-01-13 14:36:37 +010019472{
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019473 if (action != ALC_FIXUP_ACT_PROBE)
Takashi Iwai6fc398c2011-01-13 14:36:37 +010019474 return;
Todd Broch6be79482010-12-07 16:51:05 -080019475 if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT,
19476 (0x3b << AC_AMPCAP_OFFSET_SHIFT) |
19477 (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) |
19478 (0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) |
19479 (0 << AC_AMPCAP_MUTE_SHIFT)))
19480 printk(KERN_WARNING
19481 "hda_codec: failed to override amp caps for NID 0x2\n");
19482}
19483
David Henningsson6cb3b702010-09-09 08:51:44 +020019484enum {
Daniel T Chen2df03512010-10-10 22:39:28 -040019485 ALC662_FIXUP_ASPIRE,
David Henningsson6cb3b702010-09-09 08:51:44 +020019486 ALC662_FIXUP_IDEAPAD,
Todd Broch6be79482010-12-07 16:51:05 -080019487 ALC272_FIXUP_MARIO,
Anisse Astierd2ebd472011-01-20 12:36:21 +010019488 ALC662_FIXUP_CZC_P10T,
David Henningsson6cb3b702010-09-09 08:51:44 +020019489};
19490
19491static const struct alc_fixup alc662_fixups[] = {
Daniel T Chen2df03512010-10-10 22:39:28 -040019492 [ALC662_FIXUP_ASPIRE] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019493 .type = ALC_FIXUP_PINS,
19494 .v.pins = (const struct alc_pincfg[]) {
Daniel T Chen2df03512010-10-10 22:39:28 -040019495 { 0x15, 0x99130112 }, /* subwoofer */
19496 { }
19497 }
19498 },
David Henningsson6cb3b702010-09-09 08:51:44 +020019499 [ALC662_FIXUP_IDEAPAD] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019500 .type = ALC_FIXUP_PINS,
19501 .v.pins = (const struct alc_pincfg[]) {
David Henningsson6cb3b702010-09-09 08:51:44 +020019502 { 0x17, 0x99130112 }, /* subwoofer */
19503 { }
19504 }
19505 },
Todd Broch6be79482010-12-07 16:51:05 -080019506 [ALC272_FIXUP_MARIO] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019507 .type = ALC_FIXUP_FUNC,
19508 .v.func = alc272_fixup_mario,
Anisse Astierd2ebd472011-01-20 12:36:21 +010019509 },
19510 [ALC662_FIXUP_CZC_P10T] = {
19511 .type = ALC_FIXUP_VERBS,
19512 .v.verbs = (const struct hda_verb[]) {
19513 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
19514 {}
19515 }
19516 },
David Henningsson6cb3b702010-09-09 08:51:44 +020019517};
19518
19519static struct snd_pci_quirk alc662_fixup_tbl[] = {
David Henningssona6c47a82011-02-10 15:39:19 +010019520 SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
Daniel T Chen2df03512010-10-10 22:39:28 -040019521 SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
Daniel T Chena0e90ac2010-11-20 10:20:35 -050019522 SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
Valentine Sinitsynd4118582010-10-01 22:24:08 +060019523 SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
David Henningsson6cb3b702010-09-09 08:51:44 +020019524 SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
Anisse Astierd2ebd472011-01-20 12:36:21 +010019525 SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
David Henningsson6cb3b702010-09-09 08:51:44 +020019526 {}
19527};
19528
Todd Broch6be79482010-12-07 16:51:05 -080019529static const struct alc_model_fixup alc662_fixup_models[] = {
19530 {.id = ALC272_FIXUP_MARIO, .name = "mario"},
19531 {}
19532};
David Henningsson6cb3b702010-09-09 08:51:44 +020019533
19534
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019535static int patch_alc662(struct hda_codec *codec)
19536{
19537 struct alc_spec *spec;
19538 int err, board_config;
Kailang Yang693194f2010-10-21 08:51:48 +020019539 int coef;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019540
19541 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
19542 if (!spec)
19543 return -ENOMEM;
19544
19545 codec->spec = spec;
19546
Kailang Yangda00c242010-03-19 11:23:45 +010019547 alc_auto_parse_customize_define(codec);
19548
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020019549 alc_fix_pll_init(codec, 0x20, 0x04, 15);
19550
Kailang Yang693194f2010-10-21 08:51:48 +020019551 coef = alc_read_coef_idx(codec, 0);
19552 if (coef == 0x8020 || coef == 0x8011)
Kailang Yangc027ddc2010-03-19 11:33:06 +010019553 alc_codec_rename(codec, "ALC661");
Kailang Yang693194f2010-10-21 08:51:48 +020019554 else if (coef & (1 << 14) &&
19555 codec->bus->pci->subsystem_vendor == 0x1025 &&
19556 spec->cdefine.platform_type == 1)
Kailang Yangc027ddc2010-03-19 11:33:06 +010019557 alc_codec_rename(codec, "ALC272X");
Kailang Yang693194f2010-10-21 08:51:48 +020019558 else if (coef == 0x4011)
19559 alc_codec_rename(codec, "ALC656");
Kailang Yang274693f2009-12-03 10:07:50 +010019560
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019561 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
19562 alc662_models,
19563 alc662_cfg_tbl);
19564 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020019565 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
19566 codec->chip_name);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019567 board_config = ALC662_AUTO;
19568 }
19569
19570 if (board_config == ALC662_AUTO) {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019571 alc_pick_fixup(codec, alc662_fixup_models,
19572 alc662_fixup_tbl, alc662_fixups);
19573 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019574 /* automatic parse from the BIOS config */
19575 err = alc662_parse_auto_config(codec);
19576 if (err < 0) {
19577 alc_free(codec);
19578 return err;
Takashi Iwai8c87286f2007-06-19 12:11:16 +020019579 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019580 printk(KERN_INFO
19581 "hda_codec: Cannot set up configuration "
19582 "from BIOS. Using base mode...\n");
19583 board_config = ALC662_3ST_2ch_DIG;
19584 }
19585 }
19586
Takashi Iwaidc1eae22010-07-29 15:30:02 +020019587 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020019588 err = snd_hda_attach_beep_device(codec, 0x1);
19589 if (err < 0) {
19590 alc_free(codec);
19591 return err;
19592 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090019593 }
19594
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019595 if (board_config != ALC662_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020019596 setup_preset(codec, &alc662_presets[board_config]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019597
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019598 spec->stream_analog_playback = &alc662_pcm_analog_playback;
19599 spec->stream_analog_capture = &alc662_pcm_analog_capture;
19600
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019601 spec->stream_digital_playback = &alc662_pcm_digital_playback;
19602 spec->stream_digital_capture = &alc662_pcm_digital_capture;
19603
Takashi Iwaidd704692009-08-11 08:45:11 +020019604 if (!spec->adc_nids) {
19605 spec->adc_nids = alc662_adc_nids;
19606 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
19607 }
19608 if (!spec->capsrc_nids)
19609 spec->capsrc_nids = alc662_capsrc_nids;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019610
Takashi Iwaif9e336f2008-10-31 16:37:07 +010019611 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020019612 set_capture_mixer(codec);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010019613
Takashi Iwaidc1eae22010-07-29 15:30:02 +020019614 if (has_cdefine_beep(codec)) {
Kailang Yangda00c242010-03-19 11:23:45 +010019615 switch (codec->vendor_id) {
19616 case 0x10ec0662:
19617 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
19618 break;
19619 case 0x10ec0272:
19620 case 0x10ec0663:
19621 case 0x10ec0665:
19622 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
19623 break;
19624 case 0x10ec0273:
19625 set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
19626 break;
19627 }
Kailang Yangcec27c82010-02-04 14:18:18 +010019628 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010019629 spec->vmaster_nid = 0x02;
19630
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019631 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
19632
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019633 codec->patch_ops = alc_patch_ops;
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019634 if (board_config == ALC662_AUTO)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019635 spec->init_hook = alc662_auto_init;
David Henningsson6cb3b702010-09-09 08:51:44 +020019636
Kailang Yangbf1b0222010-10-21 08:49:56 +020019637 alc_init_jacks(codec);
19638
Takashi Iwaicb53c622007-08-10 17:21:45 +020019639#ifdef CONFIG_SND_HDA_POWER_SAVE
19640 if (!spec->loopback.amplist)
19641 spec->loopback.amplist = alc662_loopbacks;
19642#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019643
19644 return 0;
19645}
19646
Kailang Yang274693f2009-12-03 10:07:50 +010019647static int patch_alc888(struct hda_codec *codec)
19648{
19649 if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){
19650 kfree(codec->chip_name);
Kailang Yang01e0f132010-11-22 10:59:36 +010019651 if (codec->vendor_id == 0x10ec0887)
19652 codec->chip_name = kstrdup("ALC887-VD", GFP_KERNEL);
19653 else
19654 codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010019655 if (!codec->chip_name) {
19656 alc_free(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010019657 return -ENOMEM;
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010019658 }
19659 return patch_alc662(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010019660 }
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010019661 return patch_alc882(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010019662}
19663
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019664/*
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019665 * ALC680 support
19666 */
Kailang Yangc69aefa2010-08-17 10:39:22 +020019667#define ALC680_DIGIN_NID ALC880_DIGIN_NID
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019668#define ALC680_DIGOUT_NID ALC880_DIGOUT_NID
19669#define alc680_modes alc260_modes
19670
19671static hda_nid_t alc680_dac_nids[3] = {
19672 /* Lout1, Lout2, hp */
19673 0x02, 0x03, 0x04
19674};
19675
19676static hda_nid_t alc680_adc_nids[3] = {
19677 /* ADC0-2 */
19678 /* DMIC, MIC, Line-in*/
19679 0x07, 0x08, 0x09
19680};
19681
Kailang Yangc69aefa2010-08-17 10:39:22 +020019682/*
19683 * Analog capture ADC cgange
19684 */
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019685static void alc680_rec_autoswitch(struct hda_codec *codec)
19686{
19687 struct alc_spec *spec = codec->spec;
19688 struct auto_pin_cfg *cfg = &spec->autocfg;
19689 int pin_found = 0;
19690 int type_found = AUTO_PIN_LAST;
19691 hda_nid_t nid;
19692 int i;
19693
19694 for (i = 0; i < cfg->num_inputs; i++) {
19695 nid = cfg->inputs[i].pin;
19696 if (!(snd_hda_query_pin_caps(codec, nid) &
19697 AC_PINCAP_PRES_DETECT))
19698 continue;
19699 if (snd_hda_jack_detect(codec, nid)) {
19700 if (cfg->inputs[i].type < type_found) {
19701 type_found = cfg->inputs[i].type;
19702 pin_found = nid;
19703 }
19704 }
19705 }
19706
19707 nid = 0x07;
19708 if (pin_found)
19709 snd_hda_get_connections(codec, pin_found, &nid, 1);
19710
19711 if (nid != spec->cur_adc)
19712 __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
19713 spec->cur_adc = nid;
19714 snd_hda_codec_setup_stream(codec, nid, spec->cur_adc_stream_tag, 0,
19715 spec->cur_adc_format);
19716}
19717
Kailang Yangc69aefa2010-08-17 10:39:22 +020019718static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
19719 struct hda_codec *codec,
19720 unsigned int stream_tag,
19721 unsigned int format,
19722 struct snd_pcm_substream *substream)
19723{
19724 struct alc_spec *spec = codec->spec;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019725
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019726 spec->cur_adc = 0x07;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019727 spec->cur_adc_stream_tag = stream_tag;
19728 spec->cur_adc_format = format;
19729
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019730 alc680_rec_autoswitch(codec);
Kailang Yangc69aefa2010-08-17 10:39:22 +020019731 return 0;
19732}
19733
19734static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
19735 struct hda_codec *codec,
19736 struct snd_pcm_substream *substream)
19737{
19738 snd_hda_codec_cleanup_stream(codec, 0x07);
19739 snd_hda_codec_cleanup_stream(codec, 0x08);
19740 snd_hda_codec_cleanup_stream(codec, 0x09);
19741 return 0;
19742}
19743
19744static struct hda_pcm_stream alc680_pcm_analog_auto_capture = {
19745 .substreams = 1, /* can be overridden */
19746 .channels_min = 2,
19747 .channels_max = 2,
19748 /* NID is set in alc_build_pcms */
19749 .ops = {
19750 .prepare = alc680_capture_pcm_prepare,
19751 .cleanup = alc680_capture_pcm_cleanup
19752 },
19753};
19754
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019755static struct snd_kcontrol_new alc680_base_mixer[] = {
19756 /* output mixer control */
19757 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
19758 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
19759 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT),
19760 HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010019761 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x12, 0, HDA_INPUT),
19762 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
19763 HDA_CODEC_VOLUME("Line In Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019764 { }
19765};
19766
Kailang Yangc69aefa2010-08-17 10:39:22 +020019767static struct hda_bind_ctls alc680_bind_cap_vol = {
19768 .ops = &snd_hda_bind_vol,
19769 .values = {
19770 HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
19771 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
19772 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
19773 0
19774 },
19775};
19776
19777static struct hda_bind_ctls alc680_bind_cap_switch = {
19778 .ops = &snd_hda_bind_sw,
19779 .values = {
19780 HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
19781 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
19782 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
19783 0
19784 },
19785};
19786
19787static struct snd_kcontrol_new alc680_master_capture_mixer[] = {
19788 HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol),
19789 HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch),
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019790 { } /* end */
19791};
19792
19793/*
19794 * generic initialization of ADC, input mixers and output mixers
19795 */
19796static struct hda_verb alc680_init_verbs[] = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019797 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
19798 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
19799 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019800
Kailang Yangc69aefa2010-08-17 10:39:22 +020019801 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
19802 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
19803 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
19804 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
19805 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
19806 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019807
19808 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19809 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19810 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19811 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19812 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yangc69aefa2010-08-17 10:39:22 +020019813
19814 {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
19815 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019816 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Kailang Yangc69aefa2010-08-17 10:39:22 +020019817
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019818 { }
19819};
19820
Kailang Yangc69aefa2010-08-17 10:39:22 +020019821/* toggle speaker-output according to the hp-jack state */
19822static void alc680_base_setup(struct hda_codec *codec)
19823{
19824 struct alc_spec *spec = codec->spec;
19825
19826 spec->autocfg.hp_pins[0] = 0x16;
19827 spec->autocfg.speaker_pins[0] = 0x14;
19828 spec->autocfg.speaker_pins[1] = 0x15;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019829 spec->autocfg.num_inputs = 2;
19830 spec->autocfg.inputs[0].pin = 0x18;
19831 spec->autocfg.inputs[0].type = AUTO_PIN_MIC;
19832 spec->autocfg.inputs[1].pin = 0x19;
Takashi Iwai86e29592010-09-09 14:50:17 +020019833 spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019834}
19835
19836static void alc680_unsol_event(struct hda_codec *codec,
19837 unsigned int res)
19838{
19839 if ((res >> 26) == ALC880_HP_EVENT)
19840 alc_automute_amp(codec);
19841 if ((res >> 26) == ALC880_MIC_EVENT)
19842 alc680_rec_autoswitch(codec);
19843}
19844
19845static void alc680_inithook(struct hda_codec *codec)
19846{
19847 alc_automute_amp(codec);
19848 alc680_rec_autoswitch(codec);
19849}
19850
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019851/* create input playback/capture controls for the given pin */
19852static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
19853 const char *ctlname, int idx)
19854{
19855 hda_nid_t dac;
19856 int err;
19857
19858 switch (nid) {
19859 case 0x14:
19860 dac = 0x02;
19861 break;
19862 case 0x15:
19863 dac = 0x03;
19864 break;
19865 case 0x16:
19866 dac = 0x04;
19867 break;
19868 default:
19869 return 0;
19870 }
19871 if (spec->multiout.dac_nids[0] != dac &&
19872 spec->multiout.dac_nids[1] != dac) {
19873 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
19874 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
19875 HDA_OUTPUT));
19876 if (err < 0)
19877 return err;
19878
19879 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
19880 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
19881
19882 if (err < 0)
19883 return err;
19884 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
19885 }
19886
19887 return 0;
19888}
19889
19890/* add playback controls from the parsed DAC table */
19891static int alc680_auto_create_multi_out_ctls(struct alc_spec *spec,
19892 const struct auto_pin_cfg *cfg)
19893{
19894 hda_nid_t nid;
19895 int err;
19896
19897 spec->multiout.dac_nids = spec->private_dac_nids;
19898
19899 nid = cfg->line_out_pins[0];
19900 if (nid) {
19901 const char *name;
19902 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
19903 name = "Speaker";
19904 else
19905 name = "Front";
19906 err = alc680_new_analog_output(spec, nid, name, 0);
19907 if (err < 0)
19908 return err;
19909 }
19910
19911 nid = cfg->speaker_pins[0];
19912 if (nid) {
19913 err = alc680_new_analog_output(spec, nid, "Speaker", 0);
19914 if (err < 0)
19915 return err;
19916 }
19917 nid = cfg->hp_pins[0];
19918 if (nid) {
19919 err = alc680_new_analog_output(spec, nid, "Headphone", 0);
19920 if (err < 0)
19921 return err;
19922 }
19923
19924 return 0;
19925}
19926
19927static void alc680_auto_set_output_and_unmute(struct hda_codec *codec,
19928 hda_nid_t nid, int pin_type)
19929{
19930 alc_set_pin_output(codec, nid, pin_type);
19931}
19932
19933static void alc680_auto_init_multi_out(struct hda_codec *codec)
19934{
19935 struct alc_spec *spec = codec->spec;
19936 hda_nid_t nid = spec->autocfg.line_out_pins[0];
19937 if (nid) {
19938 int pin_type = get_pin_type(spec->autocfg.line_out_type);
19939 alc680_auto_set_output_and_unmute(codec, nid, pin_type);
19940 }
19941}
19942
19943static void alc680_auto_init_hp_out(struct hda_codec *codec)
19944{
19945 struct alc_spec *spec = codec->spec;
19946 hda_nid_t pin;
19947
19948 pin = spec->autocfg.hp_pins[0];
19949 if (pin)
19950 alc680_auto_set_output_and_unmute(codec, pin, PIN_HP);
19951 pin = spec->autocfg.speaker_pins[0];
19952 if (pin)
19953 alc680_auto_set_output_and_unmute(codec, pin, PIN_OUT);
19954}
19955
19956/* pcm configuration: identical with ALC880 */
19957#define alc680_pcm_analog_playback alc880_pcm_analog_playback
19958#define alc680_pcm_analog_capture alc880_pcm_analog_capture
19959#define alc680_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
19960#define alc680_pcm_digital_playback alc880_pcm_digital_playback
Kailang Yangc69aefa2010-08-17 10:39:22 +020019961#define alc680_pcm_digital_capture alc880_pcm_digital_capture
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019962
19963/*
19964 * BIOS auto configuration
19965 */
19966static int alc680_parse_auto_config(struct hda_codec *codec)
19967{
19968 struct alc_spec *spec = codec->spec;
19969 int err;
19970 static hda_nid_t alc680_ignore[] = { 0 };
19971
19972 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
19973 alc680_ignore);
19974 if (err < 0)
19975 return err;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019976
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019977 if (!spec->autocfg.line_outs) {
19978 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
19979 spec->multiout.max_channels = 2;
19980 spec->no_analog = 1;
19981 goto dig_only;
19982 }
19983 return 0; /* can't find valid BIOS pin config */
19984 }
19985 err = alc680_auto_create_multi_out_ctls(spec, &spec->autocfg);
19986 if (err < 0)
19987 return err;
19988
19989 spec->multiout.max_channels = 2;
19990
19991 dig_only:
19992 /* digital only support output */
Takashi Iwai757899a2010-07-30 10:48:14 +020019993 alc_auto_parse_digital(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019994 if (spec->kctls.list)
19995 add_mixer(spec, spec->kctls.list);
19996
19997 add_verb(spec, alc680_init_verbs);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019998
19999 err = alc_auto_add_mic_boost(codec);
20000 if (err < 0)
20001 return err;
20002
20003 return 1;
20004}
20005
20006#define alc680_auto_init_analog_input alc882_auto_init_analog_input
20007
20008/* init callback for auto-configuration model -- overriding the default init */
20009static void alc680_auto_init(struct hda_codec *codec)
20010{
20011 struct alc_spec *spec = codec->spec;
20012 alc680_auto_init_multi_out(codec);
20013 alc680_auto_init_hp_out(codec);
20014 alc680_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020020015 alc_auto_init_digital(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020016 if (spec->unsol_event)
20017 alc_inithook(codec);
20018}
20019
20020/*
20021 * configuration and preset
20022 */
Takashi Iwaiea734962011-01-17 11:29:34 +010020023static const char * const alc680_models[ALC680_MODEL_LAST] = {
Takashi Iwaid4a86d82010-06-23 17:51:26 +020020024 [ALC680_BASE] = "base",
20025 [ALC680_AUTO] = "auto",
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020026};
20027
20028static struct snd_pci_quirk alc680_cfg_tbl[] = {
20029 SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE),
20030 {}
20031};
20032
20033static struct alc_config_preset alc680_presets[] = {
20034 [ALC680_BASE] = {
20035 .mixers = { alc680_base_mixer },
Kailang Yangc69aefa2010-08-17 10:39:22 +020020036 .cap_mixer = alc680_master_capture_mixer,
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020037 .init_verbs = { alc680_init_verbs },
20038 .num_dacs = ARRAY_SIZE(alc680_dac_nids),
20039 .dac_nids = alc680_dac_nids,
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020040 .dig_out_nid = ALC680_DIGOUT_NID,
20041 .num_channel_mode = ARRAY_SIZE(alc680_modes),
20042 .channel_mode = alc680_modes,
Kailang Yangc69aefa2010-08-17 10:39:22 +020020043 .unsol_event = alc680_unsol_event,
20044 .setup = alc680_base_setup,
20045 .init_hook = alc680_inithook,
20046
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020047 },
20048};
20049
20050static int patch_alc680(struct hda_codec *codec)
20051{
20052 struct alc_spec *spec;
20053 int board_config;
20054 int err;
20055
20056 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
20057 if (spec == NULL)
20058 return -ENOMEM;
20059
20060 codec->spec = spec;
20061
20062 board_config = snd_hda_check_board_config(codec, ALC680_MODEL_LAST,
20063 alc680_models,
20064 alc680_cfg_tbl);
20065
20066 if (board_config < 0 || board_config >= ALC680_MODEL_LAST) {
20067 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
20068 codec->chip_name);
20069 board_config = ALC680_AUTO;
20070 }
20071
20072 if (board_config == ALC680_AUTO) {
20073 /* automatic parse from the BIOS config */
20074 err = alc680_parse_auto_config(codec);
20075 if (err < 0) {
20076 alc_free(codec);
20077 return err;
20078 } else if (!err) {
20079 printk(KERN_INFO
20080 "hda_codec: Cannot set up configuration "
20081 "from BIOS. Using base mode...\n");
20082 board_config = ALC680_BASE;
20083 }
20084 }
20085
20086 if (board_config != ALC680_AUTO)
20087 setup_preset(codec, &alc680_presets[board_config]);
20088
20089 spec->stream_analog_playback = &alc680_pcm_analog_playback;
Kailang Yangc69aefa2010-08-17 10:39:22 +020020090 spec->stream_analog_capture = &alc680_pcm_analog_auto_capture;
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020091 spec->stream_digital_playback = &alc680_pcm_digital_playback;
Kailang Yangc69aefa2010-08-17 10:39:22 +020020092 spec->stream_digital_capture = &alc680_pcm_digital_capture;
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020093
20094 if (!spec->adc_nids) {
20095 spec->adc_nids = alc680_adc_nids;
20096 spec->num_adc_nids = ARRAY_SIZE(alc680_adc_nids);
20097 }
20098
20099 if (!spec->cap_mixer)
20100 set_capture_mixer(codec);
20101
20102 spec->vmaster_nid = 0x02;
20103
20104 codec->patch_ops = alc_patch_ops;
20105 if (board_config == ALC680_AUTO)
20106 spec->init_hook = alc680_auto_init;
20107
20108 return 0;
20109}
20110
20111/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070020112 * patch entries
20113 */
Takashi Iwai1289e9e2008-11-27 15:47:11 +010020114static struct hda_codec_preset snd_hda_preset_realtek[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070020115 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010020116 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010020117 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020020118 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010020119 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010020120 { .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +020020121 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010020122 { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010020123 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020020124 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010020125 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
20126 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
20127 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020020128 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
Takashi Iwai4953550a2009-06-30 15:28:30 +020020129 .patch = patch_alc882 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020020130 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
20131 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020020132 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Kailang Yangcec27c82010-02-04 14:18:18 +010020133 { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
Kailang Yang6227cdc2010-02-25 08:36:52 +010020134 { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020135 { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010020136 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070020137 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020020138 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
Clive Messer669faba2008-09-30 15:49:13 +020020139 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
Takashi Iwai4953550a2009-06-30 15:28:30 +020020140 .patch = patch_alc882 },
Takashi Iwaicb308f92008-04-16 14:13:29 +020020141 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai4953550a2009-06-30 15:28:30 +020020142 .patch = patch_alc882 },
Kailang Yangdf694da2005-12-05 19:42:22 +010020143 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Kailang Yang01e0f132010-11-22 10:59:36 +010020144 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc888 },
Kailang Yang44426082008-10-15 11:18:05 +020020145 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
Takashi Iwai4953550a2009-06-30 15:28:30 +020020146 .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010020147 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020020148 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010020149 { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070020150 {} /* terminator */
20151};
Takashi Iwai1289e9e2008-11-27 15:47:11 +010020152
20153MODULE_ALIAS("snd-hda-codec-id:10ec*");
20154
20155MODULE_LICENSE("GPL");
20156MODULE_DESCRIPTION("Realtek HD-audio codec");
20157
20158static struct hda_codec_preset_list realtek_list = {
20159 .preset = snd_hda_preset_realtek,
20160 .owner = THIS_MODULE,
20161};
20162
20163static int __init patch_realtek_init(void)
20164{
20165 return snd_hda_add_codec_preset(&realtek_list);
20166}
20167
20168static void __exit patch_realtek_exit(void)
20169{
20170 snd_hda_delete_codec_preset(&realtek_list);
20171}
20172
20173module_init(patch_realtek_init)
20174module_exit(patch_realtek_exit)