blob: c74ca39a0b8e266d50e8415df79d25e3a37b1f77 [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>
31#include "hda_codec.h"
32#include "hda_local.h"
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090033#include "hda_beep.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
Kailang Yangccc656c2006-10-17 12:32:26 +020035#define ALC880_FRONT_EVENT 0x01
36#define ALC880_DCVOL_EVENT 0x02
37#define ALC880_HP_EVENT 0x04
38#define ALC880_MIC_EVENT 0x08
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
40/* ALC880 board config type */
41enum {
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 ALC880_3ST,
43 ALC880_3ST_DIG,
44 ALC880_5ST,
45 ALC880_5ST_DIG,
46 ALC880_W810,
Takashi Iwaidfc0ff62005-05-12 14:31:49 +020047 ALC880_Z71V,
Takashi Iwaib6482d42005-06-27 15:32:43 +020048 ALC880_6ST,
Takashi Iwai16ded522005-06-10 19:58:24 +020049 ALC880_6ST_DIG,
50 ALC880_F1734,
51 ALC880_ASUS,
52 ALC880_ASUS_DIG,
53 ALC880_ASUS_W1V,
Kailang Yangdf694da2005-12-05 19:42:22 +010054 ALC880_ASUS_DIG2,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +010055 ALC880_FUJITSU,
Takashi Iwai16ded522005-06-10 19:58:24 +020056 ALC880_UNIWILL_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +020057 ALC880_UNIWILL,
58 ALC880_UNIWILL_P53,
Kailang Yangdf694da2005-12-05 19:42:22 +010059 ALC880_CLEVO,
60 ALC880_TCL_S700,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010061 ALC880_LG,
Takashi Iwaid6815182006-03-23 16:06:23 +010062 ALC880_LG_LW,
Takashi Iwaidf99cd32008-04-25 15:25:04 +020063 ALC880_MEDION_RIM,
Takashi Iwaie9edcee2005-06-13 14:16:38 +020064#ifdef CONFIG_SND_DEBUG
65 ALC880_TEST,
66#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010067 ALC880_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020068 ALC880_MODEL_LAST /* last tag */
69};
70
71/* ALC260 models */
72enum {
73 ALC260_BASIC,
74 ALC260_HP,
Kailang Yang3f878302008-08-26 13:02:23 +020075 ALC260_HP_DC7600,
Kailang Yangdf694da2005-12-05 19:42:22 +010076 ALC260_HP_3013,
77 ALC260_FUJITSU_S702X,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +010078 ALC260_ACER,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020079 ALC260_WILL,
80 ALC260_REPLACER_672V,
Michael Schwingencc959482009-02-22 18:58:45 +010081 ALC260_FAVORIT100,
Jonathan Woithe7cf51e482006-02-09 12:01:26 +010082#ifdef CONFIG_SND_DEBUG
83 ALC260_TEST,
84#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010085 ALC260_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020086 ALC260_MODEL_LAST /* last tag */
Linus Torvalds1da177e2005-04-16 15:20:36 -070087};
88
Kailang Yangdf694da2005-12-05 19:42:22 +010089/* ALC262 models */
90enum {
91 ALC262_BASIC,
Kailang Yangccc656c2006-10-17 12:32:26 +020092 ALC262_HIPPO,
93 ALC262_HIPPO_1,
Takashi Iwai834be882006-03-01 14:16:17 +010094 ALC262_FUJITSU,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020095 ALC262_HP_BPC,
Kailang Yangcd7509a2007-01-26 18:33:17 +010096 ALC262_HP_BPC_D7000_WL,
97 ALC262_HP_BPC_D7000_WF,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010098 ALC262_HP_TC_T5735,
Kailang Yang8c427222008-01-10 13:03:59 +010099 ALC262_HP_RP5700,
Takashi Iwai304dcaa2006-07-25 14:51:16 +0200100 ALC262_BENQ_ED8,
Kailang Yang272a5272007-05-14 11:00:38 +0200101 ALC262_SONY_ASSAMD,
Kailang Yang83c34212007-07-05 11:43:05 +0200102 ALC262_BENQ_T31,
Tobin Davisf651b502007-10-26 12:40:47 +0200103 ALC262_ULTRA,
Jiang zhe0e31daf2008-03-20 12:12:39 +0100104 ALC262_LENOVO_3000,
Pascal Terjane8f9ae22008-08-04 14:36:05 +0200105 ALC262_NEC,
Kailang Yang4e555fe2008-08-26 13:05:55 +0200106 ALC262_TOSHIBA_S06,
Hiroshi Miura9f99a632008-08-28 16:09:06 +0200107 ALC262_TOSHIBA_RX1,
Tony Vroonba340e82009-02-02 19:01:30 +0000108 ALC262_TYAN,
Kailang Yangdf694da2005-12-05 19:42:22 +0100109 ALC262_AUTO,
110 ALC262_MODEL_LAST /* last tag */
111};
112
Kailang Yanga361d842007-06-05 12:30:55 +0200113/* ALC268 models */
114enum {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +0200115 ALC267_QUANTA_IL1,
Kailang Yanga361d842007-06-05 12:30:55 +0200116 ALC268_3ST,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200117 ALC268_TOSHIBA,
Takashi Iwaid2738092007-08-16 14:59:45 +0200118 ALC268_ACER,
Takashi Iwaic238b4f2008-11-05 14:57:20 +0100119 ALC268_ACER_DMIC,
Kailang Yang8ef355d2008-08-26 13:10:22 +0200120 ALC268_ACER_ASPIRE_ONE,
Takashi Iwai3866f0b2008-01-15 12:37:42 +0100121 ALC268_DELL,
Mirco Tischlerf12462c2008-02-04 12:33:59 +0100122 ALC268_ZEPTO,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +0100123#ifdef CONFIG_SND_DEBUG
124 ALC268_TEST,
125#endif
Kailang Yanga361d842007-06-05 12:30:55 +0200126 ALC268_AUTO,
127 ALC268_MODEL_LAST /* last tag */
128};
129
Kailang Yangf6a92242007-12-13 16:52:54 +0100130/* ALC269 models */
131enum {
132 ALC269_BASIC,
Kailang Yang60db6b52008-08-26 13:13:00 +0200133 ALC269_QUANTA_FL1,
Kailang Yang84898e82010-02-04 14:16:14 +0100134 ALC269_AMIC,
135 ALC269_DMIC,
136 ALC269VB_AMIC,
137 ALC269VB_DMIC,
Takashi Iwai26f5df22008-11-03 17:39:46 +0100138 ALC269_FUJITSU,
Tony Vroon64154832008-11-06 15:08:49 +0000139 ALC269_LIFEBOOK,
Kailang Yangf6a92242007-12-13 16:52:54 +0100140 ALC269_AUTO,
141 ALC269_MODEL_LAST /* last tag */
142};
143
Kailang Yangdf694da2005-12-05 19:42:22 +0100144/* ALC861 models */
145enum {
146 ALC861_3ST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200147 ALC660_3ST,
Kailang Yangdf694da2005-12-05 19:42:22 +0100148 ALC861_3ST_DIG,
149 ALC861_6ST_DIG,
Takashi Iwai22309c32006-08-09 16:57:28 +0200150 ALC861_UNIWILL_M31,
Tobin Davisa53d1ae2006-10-17 12:00:28 +0200151 ALC861_TOSHIBA,
Mariusz Domanski7cdbff92006-10-23 13:42:56 +0200152 ALC861_ASUS,
Takashi Iwai56bb0ca2006-11-22 11:52:52 +0100153 ALC861_ASUS_LAPTOP,
Kailang Yangdf694da2005-12-05 19:42:22 +0100154 ALC861_AUTO,
155 ALC861_MODEL_LAST,
156};
157
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100158/* ALC861-VD models */
159enum {
160 ALC660VD_3ST,
Mike Crash6963f842007-06-25 12:12:51 +0200161 ALC660VD_3ST_DIG,
Takashi Iwai13c94742008-11-05 08:06:08 +0100162 ALC660VD_ASUS_V1S,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100163 ALC861VD_3ST,
164 ALC861VD_3ST_DIG,
165 ALC861VD_6ST_DIG,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200166 ALC861VD_LENOVO,
Kailang Yang272a5272007-05-14 11:00:38 +0200167 ALC861VD_DALLAS,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200168 ALC861VD_HP,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100169 ALC861VD_AUTO,
170 ALC861VD_MODEL_LAST,
171};
172
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200173/* ALC662 models */
174enum {
175 ALC662_3ST_2ch_DIG,
176 ALC662_3ST_6ch_DIG,
177 ALC662_3ST_6ch,
178 ALC662_5ST_DIG,
179 ALC662_LENOVO_101E,
Kailang Yang291702f2007-10-16 14:28:03 +0200180 ALC662_ASUS_EEEPC_P701,
Kailang Yang8c427222008-01-10 13:03:59 +0100181 ALC662_ASUS_EEEPC_EP20,
Kailang Yang6dda9f42008-05-27 12:05:31 +0200182 ALC663_ASUS_M51VA,
183 ALC663_ASUS_G71V,
184 ALC663_ASUS_H13,
185 ALC663_ASUS_G50V,
Kailang Yangf1d4e282008-08-26 14:03:29 +0200186 ALC662_ECS,
187 ALC663_ASUS_MODE1,
188 ALC662_ASUS_MODE2,
189 ALC663_ASUS_MODE3,
190 ALC663_ASUS_MODE4,
191 ALC663_ASUS_MODE5,
192 ALC663_ASUS_MODE6,
Kailang Yangebb83ee2009-12-17 12:23:00 +0100193 ALC663_ASUS_MODE7,
194 ALC663_ASUS_MODE8,
Kailang Yang622e84c2009-04-21 07:39:04 +0200195 ALC272_DELL,
196 ALC272_DELL_ZM1,
Chris Pockelé9541ba12009-05-12 08:08:53 +0200197 ALC272_SAMSUNG_NC10,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200198 ALC662_AUTO,
199 ALC662_MODEL_LAST,
200};
201
Kailang Yangdf694da2005-12-05 19:42:22 +0100202/* ALC882 models */
203enum {
204 ALC882_3ST_DIG,
205 ALC882_6ST_DIG,
Takashi Iwai4b146cb2006-07-28 14:42:36 +0200206 ALC882_ARIMA,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200207 ALC882_W2JC,
Kailang Yang272a5272007-05-14 11:00:38 +0200208 ALC882_TARGA,
209 ALC882_ASUS_A7J,
Takashi Iwai914759b2007-09-06 14:52:04 +0200210 ALC882_ASUS_A7M,
Tobin Davis9102cd12006-12-15 10:02:12 +0100211 ALC885_MACPRO,
Takashi Iwai87350ad2007-08-16 18:19:38 +0200212 ALC885_MBP3,
Kacper Szczesniak41d55452009-05-07 12:47:43 +0200213 ALC885_MB5,
Luke Yelaviche458b1f2010-02-12 16:28:29 +1100214 ALC885_MACMINI3,
Nicola Fagnanic54728d2007-07-19 23:28:52 +0200215 ALC885_IMAC24,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -0800216 ALC885_IMAC91,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200217 ALC883_3ST_2ch_DIG,
218 ALC883_3ST_6ch_DIG,
219 ALC883_3ST_6ch,
220 ALC883_6ST_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +0200221 ALC883_TARGA_DIG,
222 ALC883_TARGA_2ch_DIG,
David Heidelberger64a8be72009-06-08 16:15:18 +0200223 ALC883_TARGA_8ch_DIG,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +0200224 ALC883_ACER,
Tobin Davis2880a8672007-08-07 11:50:26 +0200225 ALC883_ACER_ASPIRE,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +0800226 ALC888_ACER_ASPIRE_4930G,
Tony Vroond2fd4b02009-06-21 00:40:10 +0100227 ALC888_ACER_ASPIRE_6530G,
Hector Martin3b315d72009-06-02 10:54:19 +0200228 ALC888_ACER_ASPIRE_8930G,
Denis Kuplyakovfc86f952009-08-25 18:15:59 +0200229 ALC888_ACER_ASPIRE_7730G,
Tobin Davisc07584c2006-10-13 12:32:16 +0200230 ALC883_MEDION,
Kailang Yangea1fb292008-08-26 12:58:38 +0200231 ALC883_MEDION_MD2,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +0100232 ALC883_LAPTOP_EAPD,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200233 ALC883_LENOVO_101E_2ch,
Kailang Yang272a5272007-05-14 11:00:38 +0200234 ALC883_LENOVO_NB0763,
Kailang Yang189609a2007-08-20 11:31:23 +0200235 ALC888_LENOVO_MS7195_DIG,
Kailang Yange2757d52008-08-26 13:17:46 +0200236 ALC888_LENOVO_SKY,
Kailang Yangea1fb292008-08-26 12:58:38 +0200237 ALC883_HAIER_W66,
Claudio Matsuoka4723c022007-07-13 14:36:19 +0200238 ALC888_3ST_HP,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +0100239 ALC888_6ST_DELL,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +0100240 ALC883_MITAC,
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -0430241 ALC883_CLEVO_M540R,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +0100242 ALC883_CLEVO_M720,
Jiang zhefb97dc62008-03-06 11:07:11 +0100243 ALC883_FUJITSU_PI2515,
Vincent Petryef8ef5f2008-11-23 11:31:41 +0800244 ALC888_FUJITSU_XA3530,
Jiang zhe17bba1b2008-06-04 12:11:07 +0200245 ALC883_3ST_6ch_INTEL,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +0200246 ALC889A_INTEL,
247 ALC889_INTEL,
Kailang Yange2757d52008-08-26 13:17:46 +0200248 ALC888_ASUS_M90V,
249 ALC888_ASUS_EEE1601,
Torben Schulzeb4c41d2009-05-18 15:02:35 +0200250 ALC889A_MB31,
Wu Fengguang3ab90932008-11-17 09:51:09 +0100251 ALC1200_ASUS_P5Q,
Guido Günther3e1647c2009-06-05 00:47:26 +0200252 ALC883_SONY_VAIO_TT,
Takashi Iwai4953550a2009-06-30 15:28:30 +0200253 ALC882_AUTO,
254 ALC882_MODEL_LAST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200255};
256
Kailang Yangdf694da2005-12-05 19:42:22 +0100257/* for GPIO Poll */
258#define GPIO_MASK 0x03
259
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200260/* extra amp-initialization sequence types */
261enum {
262 ALC_INIT_NONE,
263 ALC_INIT_DEFAULT,
264 ALC_INIT_GPIO1,
265 ALC_INIT_GPIO2,
266 ALC_INIT_GPIO3,
267};
268
Takashi Iwai6c819492009-08-10 18:47:44 +0200269struct alc_mic_route {
270 hda_nid_t pin;
271 unsigned char mux_idx;
272 unsigned char amix_idx;
273};
274
275#define MUX_IDX_UNDEF ((unsigned char)-1)
276
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277struct alc_spec {
278 /* codec parameterization */
Kailang Yangdf694da2005-12-05 19:42:22 +0100279 struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 unsigned int num_mixers;
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100281 struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Takashi Iwai45bdd1c2009-02-06 16:11:25 +0100282 unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283
Takashi Iwai2d9c6482009-10-13 08:06:55 +0200284 const struct hda_verb *init_verbs[10]; /* initialization verbs
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200285 * don't forget NULL
286 * termination!
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200287 */
288 unsigned int num_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
Takashi Iwaiaa563af2009-07-31 10:05:11 +0200290 char stream_name_analog[32]; /* analog PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 struct hda_pcm_stream *stream_analog_playback;
292 struct hda_pcm_stream *stream_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +0100293 struct hda_pcm_stream *stream_analog_alt_playback;
294 struct hda_pcm_stream *stream_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
Takashi Iwaiaa563af2009-07-31 10:05:11 +0200296 char stream_name_digital[32]; /* digital PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 struct hda_pcm_stream *stream_digital_playback;
298 struct hda_pcm_stream *stream_digital_capture;
299
300 /* playback */
Takashi Iwai16ded522005-06-10 19:58:24 +0200301 struct hda_multi_out multiout; /* playback set-up
302 * max_channels, dacs must be set
303 * dig_out_nid and hp_nid are optional
304 */
Takashi Iwai63300792008-01-24 15:31:36 +0100305 hda_nid_t alt_dac_nid;
Takashi Iwai6a05ac42009-02-13 11:19:09 +0100306 hda_nid_t slave_dig_outs[3]; /* optional - for auto-parsing */
Takashi Iwai8c441982009-01-20 18:30:20 +0100307 int dig_out_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
309 /* capture */
310 unsigned int num_adc_nids;
311 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100312 hda_nid_t *capsrc_nids;
Takashi Iwai16ded522005-06-10 19:58:24 +0200313 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
315 /* capture source */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200316 unsigned int num_mux_defs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 const struct hda_input_mux *input_mux;
318 unsigned int cur_mux[3];
Takashi Iwai6c819492009-08-10 18:47:44 +0200319 struct alc_mic_route ext_mic;
320 struct alc_mic_route int_mic;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321
322 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100323 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 int num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200325 int need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200326 int const_channel_count;
327 int ext_channel_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328
329 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100330 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200331
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200332 /* dynamic controls, init_verbs and input_mux */
333 struct auto_pin_cfg autocfg;
Takashi Iwai603c4012008-07-30 15:01:44 +0200334 struct snd_array kctls;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200335 struct hda_input_mux private_imux[3];
Takashi Iwai41923e42007-10-22 17:20:10 +0200336 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai4953550a2009-06-30 15:28:30 +0200337 hda_nid_t private_adc_nids[AUTO_CFG_MAX_OUTS];
338 hda_nid_t private_capsrc_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai834be882006-03-01 14:16:17 +0100339
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100340 /* hooks */
341 void (*init_hook)(struct hda_codec *codec);
342 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
Hector Martinf5de24b2009-12-20 22:51:31 +0100343#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -0500344 void (*power_hook)(struct hda_codec *codec);
Hector Martinf5de24b2009-12-20 22:51:31 +0100345#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100346
Takashi Iwai834be882006-03-01 14:16:17 +0100347 /* for pin sensing */
348 unsigned int sense_updated: 1;
349 unsigned int jack_present: 1;
Takashi Iwaibec15c32008-01-28 18:16:30 +0100350 unsigned int master_sw: 1;
Takashi Iwai6c819492009-08-10 18:47:44 +0200351 unsigned int auto_mic:1;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200352
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100353 /* other flags */
354 unsigned int no_analog :1; /* digital I/O only */
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200355 int init_amp;
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100356
Takashi Iwai2134ea42008-01-10 16:53:55 +0100357 /* for virtual master */
358 hda_nid_t vmaster_nid;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200359#ifdef CONFIG_SND_HDA_POWER_SAVE
360 struct hda_loopback_check loopback;
361#endif
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200362
363 /* for PLL fix */
364 hda_nid_t pll_nid;
365 unsigned int pll_coef_idx, pll_coef_bit;
Kailang Yangdf694da2005-12-05 19:42:22 +0100366};
367
368/*
369 * configuration template - to be copied to the spec instance
370 */
371struct alc_config_preset {
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200372 struct snd_kcontrol_new *mixers[5]; /* should be identical size
373 * with spec
374 */
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100375 struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Kailang Yangdf694da2005-12-05 19:42:22 +0100376 const struct hda_verb *init_verbs[5];
377 unsigned int num_dacs;
378 hda_nid_t *dac_nids;
379 hda_nid_t dig_out_nid; /* optional */
380 hda_nid_t hp_nid; /* optional */
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800381 hda_nid_t *slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100382 unsigned int num_adc_nids;
383 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100384 hda_nid_t *capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100385 hda_nid_t dig_in_nid;
386 unsigned int num_channel_mode;
387 const struct hda_channel_mode *channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200388 int need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200389 int const_channel_count;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200390 unsigned int num_mux_defs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100391 const struct hda_input_mux *input_mux;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100392 void (*unsol_event)(struct hda_codec *, unsigned int);
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200393 void (*setup)(struct hda_codec *);
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100394 void (*init_hook)(struct hda_codec *);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200395#ifdef CONFIG_SND_HDA_POWER_SAVE
396 struct hda_amp_list *loopbacks;
Daniel T Chenc97259d2009-12-27 18:52:08 -0500397 void (*power_hook)(struct hda_codec *codec);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200398#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399};
400
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
402/*
403 * input MUX handling
404 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200405static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
406 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407{
408 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
409 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200410 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
411 if (mux_idx >= spec->num_mux_defs)
412 mux_idx = 0;
413 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414}
415
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200416static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
417 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418{
419 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
420 struct alc_spec *spec = codec->spec;
421 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
422
423 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
424 return 0;
425}
426
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200427static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
428 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429{
430 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
431 struct alc_spec *spec = codec->spec;
Takashi Iwaicd896c32008-11-18 12:36:33 +0100432 const struct hda_input_mux *imux;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwaicd896c32008-11-18 12:36:33 +0100434 unsigned int mux_idx;
Takashi Iwaie1406342008-02-11 18:32:32 +0100435 hda_nid_t nid = spec->capsrc_nids ?
436 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Takashi Iwai0169b6b2009-06-22 10:50:19 +0200437 unsigned int type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438
Takashi Iwaicd896c32008-11-18 12:36:33 +0100439 mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
440 imux = &spec->input_mux[mux_idx];
441
Takashi Iwaia22d5432009-07-27 12:54:26 +0200442 type = get_wcaps_type(get_wcaps(codec, nid));
Takashi Iwai0169b6b2009-06-22 10:50:19 +0200443 if (type == AC_WID_AUD_MIX) {
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100444 /* Matrix-mixer style (e.g. ALC882) */
445 unsigned int *cur_val = &spec->cur_mux[adc_idx];
446 unsigned int i, idx;
447
448 idx = ucontrol->value.enumerated.item[0];
449 if (idx >= imux->num_items)
450 idx = imux->num_items - 1;
451 if (*cur_val == idx)
452 return 0;
453 for (i = 0; i < imux->num_items; i++) {
454 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
455 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
456 imux->items[i].index,
457 HDA_AMP_MUTE, v);
458 }
459 *cur_val = idx;
460 return 1;
461 } else {
462 /* MUX style (e.g. ALC880) */
Takashi Iwaicd896c32008-11-18 12:36:33 +0100463 return snd_hda_input_mux_put(codec, imux, ucontrol, nid,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100464 &spec->cur_mux[adc_idx]);
465 }
466}
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200467
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468/*
469 * channel mode setting
470 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200471static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
472 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473{
474 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
475 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100476 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
477 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478}
479
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200480static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
481 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482{
483 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
484 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100485 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200486 spec->num_channel_mode,
Hector Martin3b315d72009-06-02 10:54:19 +0200487 spec->ext_channel_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488}
489
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200490static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
491 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492{
493 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
494 struct alc_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200495 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
496 spec->num_channel_mode,
Hector Martin3b315d72009-06-02 10:54:19 +0200497 &spec->ext_channel_count);
498 if (err >= 0 && !spec->const_channel_count) {
499 spec->multiout.max_channels = spec->ext_channel_count;
500 if (spec->need_dac_fix)
501 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
502 }
Takashi Iwai4e195a72006-07-28 14:47:34 +0200503 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504}
505
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100507 * Control the mode of pin widget settings via the mixer. "pc" is used
Kailang Yangea1fb292008-08-26 12:58:38 +0200508 * instead of "%" to avoid consequences of accidently treating the % as
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100509 * being part of a format specifier. Maximum allowed length of a value is
510 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100511 *
512 * Note: some retasking pin complexes seem to ignore requests for input
513 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
514 * are requested. Therefore order this list so that this behaviour will not
515 * cause problems when mixer clients move through the enum sequentially.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200516 * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
517 * March 2006.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200518 */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100519static char *alc_pin_mode_names[] = {
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100520 "Mic 50pc bias", "Mic 80pc bias",
521 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100522};
523static unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100524 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100525};
526/* The control can present all 5 options, or it can limit the options based
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200527 * in the pin being assumed to be exclusively an input or an output pin. In
528 * addition, "input" pins may or may not process the mic bias option
529 * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
530 * accept requests for bias as of chip versions up to March 2006) and/or
531 * wiring in the computer.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100532 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200533#define ALC_PIN_DIR_IN 0x00
534#define ALC_PIN_DIR_OUT 0x01
535#define ALC_PIN_DIR_INOUT 0x02
536#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
537#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100538
Kailang Yangea1fb292008-08-26 12:58:38 +0200539/* Info about the pin modes supported by the different pin direction modes.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100540 * For each direction the minimum and maximum values are given.
541 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200542static signed char alc_pin_mode_dir_info[5][2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100543 { 0, 2 }, /* ALC_PIN_DIR_IN */
544 { 3, 4 }, /* ALC_PIN_DIR_OUT */
545 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200546 { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
547 { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100548};
549#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
550#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
551#define alc_pin_mode_n_items(_dir) \
552 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
553
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200554static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
555 struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200556{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100557 unsigned int item_num = uinfo->value.enumerated.item;
558 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
559
560 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200561 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100562 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
563
564 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
565 item_num = alc_pin_mode_min(dir);
566 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200567 return 0;
568}
569
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200570static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
571 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200572{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100573 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200574 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
575 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100576 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200577 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200578 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
579 AC_VERB_GET_PIN_WIDGET_CONTROL,
580 0x00);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200581
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100582 /* Find enumerated value for current pinctl setting */
583 i = alc_pin_mode_min(dir);
Roel Kluin4b35d2ca2009-08-02 13:30:45 +0200584 while (i <= alc_pin_mode_max(dir) && alc_pin_mode_values[i] != pinctl)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100585 i++;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200586 *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100587 return 0;
588}
589
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200590static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
591 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100592{
593 signed int change;
594 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
595 hda_nid_t nid = kcontrol->private_value & 0xffff;
596 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
597 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200598 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
599 AC_VERB_GET_PIN_WIDGET_CONTROL,
600 0x00);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100601
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200602 if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100603 val = alc_pin_mode_min(dir);
604
605 change = pinctl != alc_pin_mode_values[val];
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100606 if (change) {
607 /* Set pin mode to that requested */
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200608 snd_hda_codec_write_cache(codec, nid, 0,
609 AC_VERB_SET_PIN_WIDGET_CONTROL,
610 alc_pin_mode_values[val]);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100611
Kailang Yangea1fb292008-08-26 12:58:38 +0200612 /* Also enable the retasking pin's input/output as required
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100613 * for the requested pin mode. Enum values of 2 or less are
614 * input modes.
615 *
616 * Dynamically switching the input/output buffers probably
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200617 * reduces noise slightly (particularly on input) so we'll
618 * do it. However, having both input and output buffers
619 * enabled simultaneously doesn't seem to be problematic if
620 * this turns out to be necessary in the future.
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100621 */
622 if (val <= 2) {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200623 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
624 HDA_AMP_MUTE, HDA_AMP_MUTE);
625 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
626 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100627 } else {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200628 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
629 HDA_AMP_MUTE, HDA_AMP_MUTE);
630 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
631 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100632 }
633 }
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200634 return change;
635}
636
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100637#define ALC_PIN_MODE(xname, nid, dir) \
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200638 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100639 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100640 .info = alc_pin_mode_info, \
641 .get = alc_pin_mode_get, \
642 .put = alc_pin_mode_put, \
643 .private_value = nid | (dir<<16) }
Kailang Yangdf694da2005-12-05 19:42:22 +0100644
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100645/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
646 * together using a mask with more than one bit set. This control is
647 * currently used only by the ALC260 test model. At this stage they are not
648 * needed for any "production" models.
649 */
650#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200651#define alc_gpio_data_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200652
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200653static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
654 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100655{
656 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
657 hda_nid_t nid = kcontrol->private_value & 0xffff;
658 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
659 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200660 unsigned int val = snd_hda_codec_read(codec, nid, 0,
661 AC_VERB_GET_GPIO_DATA, 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100662
663 *valp = (val & mask) != 0;
664 return 0;
665}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200666static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
667 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100668{
669 signed int change;
670 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
671 hda_nid_t nid = kcontrol->private_value & 0xffff;
672 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
673 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200674 unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
675 AC_VERB_GET_GPIO_DATA,
676 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100677
678 /* Set/unset the masked GPIO bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200679 change = (val == 0 ? 0 : mask) != (gpio_data & mask);
680 if (val == 0)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100681 gpio_data &= ~mask;
682 else
683 gpio_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200684 snd_hda_codec_write_cache(codec, nid, 0,
685 AC_VERB_SET_GPIO_DATA, gpio_data);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100686
687 return change;
688}
689#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
690 { .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 Woithe5c8f8582006-02-28 11:43:27 +0100692 .info = alc_gpio_data_info, \
693 .get = alc_gpio_data_get, \
694 .put = alc_gpio_data_put, \
695 .private_value = nid | (mask<<16) }
696#endif /* CONFIG_SND_DEBUG */
697
Jonathan Woithe92621f12006-02-28 11:47:47 +0100698/* A switch control to allow the enabling of the digital IO pins on the
699 * ALC260. This is incredibly simplistic; the intention of this control is
700 * to provide something in the test model allowing digital outputs to be
701 * identified if present. If models are found which can utilise these
702 * outputs a more complete mixer control can be devised for those models if
703 * necessary.
704 */
705#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200706#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200707
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200708static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
709 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100710{
711 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
712 hda_nid_t nid = kcontrol->private_value & 0xffff;
713 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
714 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200715 unsigned int val = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100716 AC_VERB_GET_DIGI_CONVERT_1, 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100717
718 *valp = (val & mask) != 0;
719 return 0;
720}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200721static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
722 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100723{
724 signed int change;
725 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
726 hda_nid_t nid = kcontrol->private_value & 0xffff;
727 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
728 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200729 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100730 AC_VERB_GET_DIGI_CONVERT_1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200731 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100732
733 /* Set/unset the masked control bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200734 change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100735 if (val==0)
736 ctrl_data &= ~mask;
737 else
738 ctrl_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200739 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
740 ctrl_data);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100741
742 return change;
743}
744#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
745 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100746 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe92621f12006-02-28 11:47:47 +0100747 .info = alc_spdif_ctrl_info, \
748 .get = alc_spdif_ctrl_get, \
749 .put = alc_spdif_ctrl_put, \
750 .private_value = nid | (mask<<16) }
751#endif /* CONFIG_SND_DEBUG */
752
Jonathan Woithef8225f62008-01-08 12:16:54 +0100753/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
754 * Again, this is only used in the ALC26x test models to help identify when
755 * the EAPD line must be asserted for features to work.
756 */
757#ifdef CONFIG_SND_DEBUG
758#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
759
760static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
761 struct snd_ctl_elem_value *ucontrol)
762{
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;
767 unsigned int val = snd_hda_codec_read(codec, nid, 0,
768 AC_VERB_GET_EAPD_BTLENABLE, 0x00);
769
770 *valp = (val & mask) != 0;
771 return 0;
772}
773
774static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
775 struct snd_ctl_elem_value *ucontrol)
776{
777 int change;
778 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
779 hda_nid_t nid = kcontrol->private_value & 0xffff;
780 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
781 long val = *ucontrol->value.integer.value;
782 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
783 AC_VERB_GET_EAPD_BTLENABLE,
784 0x00);
785
786 /* Set/unset the masked control bit(s) as needed */
787 change = (!val ? 0 : mask) != (ctrl_data & mask);
788 if (!val)
789 ctrl_data &= ~mask;
790 else
791 ctrl_data |= mask;
792 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
793 ctrl_data);
794
795 return change;
796}
797
798#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
799 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100800 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithef8225f62008-01-08 12:16:54 +0100801 .info = alc_eapd_ctrl_info, \
802 .get = alc_eapd_ctrl_get, \
803 .put = alc_eapd_ctrl_put, \
804 .private_value = nid | (mask<<16) }
805#endif /* CONFIG_SND_DEBUG */
806
Kailang Yangdf694da2005-12-05 19:42:22 +0100807/*
Takashi Iwai23f0c042009-02-26 13:03:58 +0100808 * set up the input pin config (depending on the given auto-pin type)
809 */
810static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
811 int auto_pin_type)
812{
813 unsigned int val = PIN_IN;
814
815 if (auto_pin_type <= AUTO_PIN_FRONT_MIC) {
816 unsigned int pincap;
Takashi Iwai1327a322009-03-23 13:07:47 +0100817 pincap = snd_hda_query_pin_caps(codec, nid);
Takashi Iwai23f0c042009-02-26 13:03:58 +0100818 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
819 if (pincap & AC_PINCAP_VREF_80)
820 val = PIN_VREF80;
Takashi Iwai461c6c32009-05-25 08:06:02 +0200821 else if (pincap & AC_PINCAP_VREF_50)
822 val = PIN_VREF50;
823 else if (pincap & AC_PINCAP_VREF_100)
824 val = PIN_VREF100;
825 else if (pincap & AC_PINCAP_VREF_GRD)
826 val = PIN_VREFGRD;
Takashi Iwai23f0c042009-02-26 13:03:58 +0100827 }
828 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
829}
830
831/*
Takashi Iwaid88897e2008-10-31 15:01:37 +0100832 */
833static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix)
834{
835 if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
836 return;
837 spec->mixers[spec->num_mixers++] = mix;
838}
839
840static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
841{
842 if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
843 return;
844 spec->init_verbs[spec->num_init_verbs++] = verb;
845}
846
847/*
Kailang Yangdf694da2005-12-05 19:42:22 +0100848 * set up from the preset table
849 */
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200850static void setup_preset(struct hda_codec *codec,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200851 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100852{
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200853 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +0100854 int i;
855
856 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100857 add_mixer(spec, preset->mixers[i]);
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100858 spec->cap_mixer = preset->cap_mixer;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200859 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
860 i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100861 add_verb(spec, preset->init_verbs[i]);
Kailang Yangea1fb292008-08-26 12:58:38 +0200862
Kailang Yangdf694da2005-12-05 19:42:22 +0100863 spec->channel_mode = preset->channel_mode;
864 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200865 spec->need_dac_fix = preset->need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200866 spec->const_channel_count = preset->const_channel_count;
Kailang Yangdf694da2005-12-05 19:42:22 +0100867
Hector Martin3b315d72009-06-02 10:54:19 +0200868 if (preset->const_channel_count)
869 spec->multiout.max_channels = preset->const_channel_count;
870 else
871 spec->multiout.max_channels = spec->channel_mode[0].channels;
872 spec->ext_channel_count = spec->channel_mode[0].channels;
Kailang Yangdf694da2005-12-05 19:42:22 +0100873
874 spec->multiout.num_dacs = preset->num_dacs;
875 spec->multiout.dac_nids = preset->dac_nids;
876 spec->multiout.dig_out_nid = preset->dig_out_nid;
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800877 spec->multiout.slave_dig_outs = preset->slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100878 spec->multiout.hp_nid = preset->hp_nid;
Kailang Yangea1fb292008-08-26 12:58:38 +0200879
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200880 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200881 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200882 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100883 spec->input_mux = preset->input_mux;
884
885 spec->num_adc_nids = preset->num_adc_nids;
886 spec->adc_nids = preset->adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100887 spec->capsrc_nids = preset->capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100888 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100889
890 spec->unsol_event = preset->unsol_event;
891 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200892#ifdef CONFIG_SND_HDA_POWER_SAVE
Hector Martinf5de24b2009-12-20 22:51:31 +0100893 spec->power_hook = preset->power_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200894 spec->loopback.amplist = preset->loopbacks;
895#endif
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200896
897 if (preset->setup)
898 preset->setup(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +0100899}
900
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200901/* Enable GPIO mask and set output */
902static struct hda_verb alc_gpio1_init_verbs[] = {
903 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
904 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
905 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
906 { }
907};
908
909static struct hda_verb alc_gpio2_init_verbs[] = {
910 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
911 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
912 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
913 { }
914};
915
Kailang Yangbdd148a2007-05-08 15:19:08 +0200916static struct hda_verb alc_gpio3_init_verbs[] = {
917 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
918 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
919 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
920 { }
921};
922
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200923/*
924 * Fix hardware PLL issue
925 * On some codecs, the analog PLL gating control must be off while
926 * the default value is 1.
927 */
928static void alc_fix_pll(struct hda_codec *codec)
929{
930 struct alc_spec *spec = codec->spec;
931 unsigned int val;
932
933 if (!spec->pll_nid)
934 return;
935 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
936 spec->pll_coef_idx);
937 val = snd_hda_codec_read(codec, spec->pll_nid, 0,
938 AC_VERB_GET_PROC_COEF, 0);
939 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
940 spec->pll_coef_idx);
941 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
942 val & ~(1 << spec->pll_coef_bit));
943}
944
945static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
946 unsigned int coef_idx, unsigned int coef_bit)
947{
948 struct alc_spec *spec = codec->spec;
949 spec->pll_nid = nid;
950 spec->pll_coef_idx = coef_idx;
951 spec->pll_coef_bit = coef_bit;
952 alc_fix_pll(codec);
953}
954
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200955static void alc_automute_pin(struct hda_codec *codec)
Kailang Yangc9b58002007-10-16 14:30:01 +0200956{
957 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200958 unsigned int nid = spec->autocfg.hp_pins[0];
959 int i;
Kailang Yangc9b58002007-10-16 14:30:01 +0200960
Takashi Iwaiad87c642009-11-02 14:23:15 +0100961 if (!nid)
962 return;
Wu Fengguang864f92b2009-11-18 12:38:02 +0800963 spec->jack_present = snd_hda_jack_detect(codec, nid);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200964 for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
965 nid = spec->autocfg.speaker_pins[i];
966 if (!nid)
967 break;
968 snd_hda_codec_write(codec, nid, 0,
969 AC_VERB_SET_PIN_WIDGET_CONTROL,
970 spec->jack_present ? 0 : PIN_OUT);
971 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200972}
973
Takashi Iwai6c819492009-08-10 18:47:44 +0200974static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
975 hda_nid_t nid)
976{
977 hda_nid_t conn[HDA_MAX_NUM_INPUTS];
978 int i, nums;
979
980 nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
981 for (i = 0; i < nums; i++)
982 if (conn[i] == nid)
983 return i;
984 return -1;
985}
986
Kailang Yang7fb0d782008-10-15 11:12:35 +0200987static void alc_mic_automute(struct hda_codec *codec)
988{
989 struct alc_spec *spec = codec->spec;
Takashi Iwai6c819492009-08-10 18:47:44 +0200990 struct alc_mic_route *dead, *alive;
991 unsigned int present, type;
992 hda_nid_t cap_nid;
Kailang Yang7fb0d782008-10-15 11:12:35 +0200993
Takashi Iwaib59bdf32009-08-11 09:47:30 +0200994 if (!spec->auto_mic)
995 return;
Takashi Iwai6c819492009-08-10 18:47:44 +0200996 if (!spec->int_mic.pin || !spec->ext_mic.pin)
997 return;
998 if (snd_BUG_ON(!spec->adc_nids))
999 return;
1000
1001 cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0];
1002
Wu Fengguang864f92b2009-11-18 12:38:02 +08001003 present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
Takashi Iwai6c819492009-08-10 18:47:44 +02001004 if (present) {
1005 alive = &spec->ext_mic;
1006 dead = &spec->int_mic;
1007 } else {
1008 alive = &spec->int_mic;
1009 dead = &spec->ext_mic;
1010 }
1011
Takashi Iwai6c819492009-08-10 18:47:44 +02001012 type = get_wcaps_type(get_wcaps(codec, cap_nid));
1013 if (type == AC_WID_AUD_MIX) {
1014 /* Matrix-mixer style (e.g. ALC882) */
1015 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1016 alive->mux_idx,
1017 HDA_AMP_MUTE, 0);
1018 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1019 dead->mux_idx,
1020 HDA_AMP_MUTE, HDA_AMP_MUTE);
1021 } else {
1022 /* MUX style (e.g. ALC880) */
1023 snd_hda_codec_write_cache(codec, cap_nid, 0,
1024 AC_VERB_SET_CONNECT_SEL,
1025 alive->mux_idx);
1026 }
1027
1028 /* FIXME: analog mixer */
Kailang Yang7fb0d782008-10-15 11:12:35 +02001029}
1030
Kailang Yangc9b58002007-10-16 14:30:01 +02001031/* unsolicited event for HP jack sensing */
1032static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
1033{
1034 if (codec->vendor_id == 0x10ec0880)
1035 res >>= 28;
1036 else
1037 res >>= 26;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001038 switch (res) {
1039 case ALC880_HP_EVENT:
1040 alc_automute_pin(codec);
1041 break;
1042 case ALC880_MIC_EVENT:
Kailang Yang7fb0d782008-10-15 11:12:35 +02001043 alc_mic_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001044 break;
1045 }
Kailang Yang7fb0d782008-10-15 11:12:35 +02001046}
1047
1048static void alc_inithook(struct hda_codec *codec)
1049{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001050 alc_automute_pin(codec);
Kailang Yang7fb0d782008-10-15 11:12:35 +02001051 alc_mic_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +02001052}
1053
Kailang Yangf9423e72008-05-27 12:32:25 +02001054/* additional initialization for ALC888 variants */
1055static void alc888_coef_init(struct hda_codec *codec)
1056{
1057 unsigned int tmp;
1058
1059 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
1060 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
1061 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
Takashi Iwai37db6232009-03-05 09:40:16 +01001062 if ((tmp & 0xf0) == 0x20)
Kailang Yangf9423e72008-05-27 12:32:25 +02001063 /* alc888S-VC */
1064 snd_hda_codec_read(codec, 0x20, 0,
1065 AC_VERB_SET_PROC_COEF, 0x830);
1066 else
1067 /* alc888-VB */
1068 snd_hda_codec_read(codec, 0x20, 0,
1069 AC_VERB_SET_PROC_COEF, 0x3030);
1070}
1071
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02001072static void alc889_coef_init(struct hda_codec *codec)
1073{
1074 unsigned int tmp;
1075
1076 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
1077 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
1078 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
1079 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, tmp|0x2010);
1080}
1081
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001082/* turn on/off EAPD control (only if available) */
1083static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on)
1084{
1085 if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
1086 return;
1087 if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
1088 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
1089 on ? 2 : 0);
1090}
1091
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001092static void alc_auto_init_amp(struct hda_codec *codec, int type)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001093{
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001094 unsigned int tmp;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001095
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001096 switch (type) {
1097 case ALC_INIT_GPIO1:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001098 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
1099 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001100 case ALC_INIT_GPIO2:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001101 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
1102 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001103 case ALC_INIT_GPIO3:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001104 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
1105 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001106 case ALC_INIT_DEFAULT:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001107 switch (codec->vendor_id) {
Kailang Yangc9b58002007-10-16 14:30:01 +02001108 case 0x10ec0260:
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001109 set_eapd(codec, 0x0f, 1);
1110 set_eapd(codec, 0x10, 1);
Kailang Yangc9b58002007-10-16 14:30:01 +02001111 break;
1112 case 0x10ec0262:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001113 case 0x10ec0267:
1114 case 0x10ec0268:
Kailang Yangc9b58002007-10-16 14:30:01 +02001115 case 0x10ec0269:
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001116 case 0x10ec0270:
Takashi Iwaic6e8f2d2009-02-06 12:45:52 +01001117 case 0x10ec0272:
Kailang Yangf9423e72008-05-27 12:32:25 +02001118 case 0x10ec0660:
1119 case 0x10ec0662:
1120 case 0x10ec0663:
Kailang Yangc9b58002007-10-16 14:30:01 +02001121 case 0x10ec0862:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001122 case 0x10ec0889:
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001123 set_eapd(codec, 0x14, 1);
1124 set_eapd(codec, 0x15, 1);
Kailang Yangc9b58002007-10-16 14:30:01 +02001125 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +02001126 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001127 switch (codec->vendor_id) {
1128 case 0x10ec0260:
1129 snd_hda_codec_write(codec, 0x1a, 0,
1130 AC_VERB_SET_COEF_INDEX, 7);
1131 tmp = snd_hda_codec_read(codec, 0x1a, 0,
1132 AC_VERB_GET_PROC_COEF, 0);
1133 snd_hda_codec_write(codec, 0x1a, 0,
1134 AC_VERB_SET_COEF_INDEX, 7);
1135 snd_hda_codec_write(codec, 0x1a, 0,
1136 AC_VERB_SET_PROC_COEF,
1137 tmp | 0x2010);
1138 break;
1139 case 0x10ec0262:
1140 case 0x10ec0880:
1141 case 0x10ec0882:
1142 case 0x10ec0883:
1143 case 0x10ec0885:
Takashi Iwai4a5a4c52009-02-06 12:46:59 +01001144 case 0x10ec0887:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001145 case 0x10ec0889:
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02001146 alc889_coef_init(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +02001147 break;
Kailang Yangf9423e72008-05-27 12:32:25 +02001148 case 0x10ec0888:
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001149 alc888_coef_init(codec);
Kailang Yangf9423e72008-05-27 12:32:25 +02001150 break;
Takashi Iwai0aea7782010-01-25 15:44:11 +01001151#if 0 /* XXX: This may cause the silent output on speaker on some machines */
Kailang Yangc9b58002007-10-16 14:30:01 +02001152 case 0x10ec0267:
1153 case 0x10ec0268:
1154 snd_hda_codec_write(codec, 0x20, 0,
1155 AC_VERB_SET_COEF_INDEX, 7);
1156 tmp = snd_hda_codec_read(codec, 0x20, 0,
1157 AC_VERB_GET_PROC_COEF, 0);
1158 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001159 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001160 snd_hda_codec_write(codec, 0x20, 0,
1161 AC_VERB_SET_PROC_COEF,
1162 tmp | 0x3000);
1163 break;
Takashi Iwai0aea7782010-01-25 15:44:11 +01001164#endif /* XXX */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001165 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001166 break;
1167 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001168}
Kailang Yangea1fb292008-08-26 12:58:38 +02001169
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001170static void alc_init_auto_hp(struct hda_codec *codec)
1171{
1172 struct alc_spec *spec = codec->spec;
1173
1174 if (!spec->autocfg.hp_pins[0])
Kailang Yangc9b58002007-10-16 14:30:01 +02001175 return;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001176
Kailang Yangc9b58002007-10-16 14:30:01 +02001177 if (!spec->autocfg.speaker_pins[0]) {
Takashi Iwai2a2ed0d2009-04-28 13:01:26 +02001178 if (spec->autocfg.line_out_pins[0] &&
1179 spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
Kailang Yangc9b58002007-10-16 14:30:01 +02001180 spec->autocfg.speaker_pins[0] =
Kailang Yang8c427222008-01-10 13:03:59 +01001181 spec->autocfg.line_out_pins[0];
Kailang Yangc9b58002007-10-16 14:30:01 +02001182 else
1183 return;
1184 }
1185
Takashi Iwai2a2ed0d2009-04-28 13:01:26 +02001186 snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
1187 spec->autocfg.hp_pins[0]);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001188 snd_hda_codec_write_cache(codec, spec->autocfg.hp_pins[0], 0,
1189 AC_VERB_SET_UNSOLICITED_ENABLE,
1190 AC_USRSP_EN | ALC880_HP_EVENT);
1191 spec->unsol_event = alc_sku_unsol_event;
1192}
1193
Takashi Iwai6c819492009-08-10 18:47:44 +02001194static void alc_init_auto_mic(struct hda_codec *codec)
1195{
1196 struct alc_spec *spec = codec->spec;
1197 struct auto_pin_cfg *cfg = &spec->autocfg;
1198 hda_nid_t fixed, ext;
1199 int i;
1200
1201 /* there must be only two mic inputs exclusively */
1202 for (i = AUTO_PIN_LINE; i < AUTO_PIN_LAST; i++)
1203 if (cfg->input_pins[i])
1204 return;
1205
1206 fixed = ext = 0;
1207 for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++) {
1208 hda_nid_t nid = cfg->input_pins[i];
1209 unsigned int defcfg;
1210 if (!nid)
1211 return;
1212 defcfg = snd_hda_codec_get_pincfg(codec, nid);
1213 switch (get_defcfg_connect(defcfg)) {
1214 case AC_JACK_PORT_FIXED:
1215 if (fixed)
1216 return; /* already occupied */
1217 fixed = nid;
1218 break;
1219 case AC_JACK_PORT_COMPLEX:
1220 if (ext)
1221 return; /* already occupied */
1222 ext = nid;
1223 break;
1224 default:
1225 return; /* invalid entry */
1226 }
1227 }
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01001228 if (!ext || !fixed)
1229 return;
Takashi Iwai6c819492009-08-10 18:47:44 +02001230 if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP))
1231 return; /* no unsol support */
1232 snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x\n",
1233 ext, fixed);
1234 spec->ext_mic.pin = ext;
1235 spec->int_mic.pin = fixed;
1236 spec->ext_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
1237 spec->int_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
1238 spec->auto_mic = 1;
1239 snd_hda_codec_write_cache(codec, spec->ext_mic.pin, 0,
1240 AC_VERB_SET_UNSOLICITED_ENABLE,
1241 AC_USRSP_EN | ALC880_MIC_EVENT);
1242 spec->unsol_event = alc_sku_unsol_event;
1243}
1244
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001245/* check subsystem ID and set up device-specific initialization;
1246 * return 1 if initialized, 0 if invalid SSID
1247 */
1248/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
1249 * 31 ~ 16 : Manufacture ID
1250 * 15 ~ 8 : SKU ID
1251 * 7 ~ 0 : Assembly ID
1252 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
1253 */
1254static int alc_subsystem_id(struct hda_codec *codec,
1255 hda_nid_t porta, hda_nid_t porte,
1256 hda_nid_t portd)
1257{
1258 unsigned int ass, tmp, i;
1259 unsigned nid;
1260 struct alc_spec *spec = codec->spec;
1261
1262 ass = codec->subsystem_id & 0xffff;
1263 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
1264 goto do_sku;
1265
1266 /* invalid SSID, check the special NID pin defcfg instead */
1267 /*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04001268 * 31~30 : port connectivity
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001269 * 29~21 : reserve
1270 * 20 : PCBEEP input
1271 * 19~16 : Check sum (15:1)
1272 * 15~1 : Custom
1273 * 0 : override
1274 */
1275 nid = 0x1d;
1276 if (codec->vendor_id == 0x10ec0260)
1277 nid = 0x17;
1278 ass = snd_hda_codec_get_pincfg(codec, nid);
1279 snd_printd("realtek: No valid SSID, "
1280 "checking pincfg 0x%08x for NID 0x%x\n",
Takashi Iwaicb6605c2009-04-28 13:03:19 +02001281 ass, nid);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001282 if (!(ass & 1) && !(ass & 0x100000))
1283 return 0;
1284 if ((ass >> 30) != 1) /* no physical connection */
1285 return 0;
1286
1287 /* check sum */
1288 tmp = 0;
1289 for (i = 1; i < 16; i++) {
1290 if ((ass >> i) & 1)
1291 tmp++;
1292 }
1293 if (((ass >> 16) & 0xf) != tmp)
1294 return 0;
1295do_sku:
1296 snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
1297 ass & 0xffff, codec->vendor_id);
1298 /*
1299 * 0 : override
1300 * 1 : Swap Jack
1301 * 2 : 0 --> Desktop, 1 --> Laptop
1302 * 3~5 : External Amplifier control
1303 * 7~6 : Reserved
1304 */
1305 tmp = (ass & 0x38) >> 3; /* external Amp control */
1306 switch (tmp) {
1307 case 1:
1308 spec->init_amp = ALC_INIT_GPIO1;
1309 break;
1310 case 3:
1311 spec->init_amp = ALC_INIT_GPIO2;
1312 break;
1313 case 7:
1314 spec->init_amp = ALC_INIT_GPIO3;
1315 break;
1316 case 5:
1317 spec->init_amp = ALC_INIT_DEFAULT;
1318 break;
1319 }
1320
1321 /* is laptop or Desktop and enable the function "Mute internal speaker
1322 * when the external headphone out jack is plugged"
1323 */
1324 if (!(ass & 0x8000))
1325 return 1;
1326 /*
1327 * 10~8 : Jack location
1328 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
1329 * 14~13: Resvered
1330 * 15 : 1 --> enable the function "Mute internal speaker
1331 * when the external headphone out jack is plugged"
1332 */
Kailang Yangc9b58002007-10-16 14:30:01 +02001333 if (!spec->autocfg.hp_pins[0]) {
Takashi Iwai01d48252009-10-06 13:21:54 +02001334 hda_nid_t nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001335 tmp = (ass >> 11) & 0x3; /* HP to chassis */
1336 if (tmp == 0)
Takashi Iwai01d48252009-10-06 13:21:54 +02001337 nid = porta;
Kailang Yangc9b58002007-10-16 14:30:01 +02001338 else if (tmp == 1)
Takashi Iwai01d48252009-10-06 13:21:54 +02001339 nid = porte;
Kailang Yangc9b58002007-10-16 14:30:01 +02001340 else if (tmp == 2)
Takashi Iwai01d48252009-10-06 13:21:54 +02001341 nid = portd;
Kailang Yangc9b58002007-10-16 14:30:01 +02001342 else
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001343 return 1;
Takashi Iwai01d48252009-10-06 13:21:54 +02001344 for (i = 0; i < spec->autocfg.line_outs; i++)
1345 if (spec->autocfg.line_out_pins[i] == nid)
1346 return 1;
1347 spec->autocfg.hp_pins[0] = nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001348 }
1349
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001350 alc_init_auto_hp(codec);
Takashi Iwai6c819492009-08-10 18:47:44 +02001351 alc_init_auto_mic(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001352 return 1;
1353}
Kailang Yangea1fb292008-08-26 12:58:38 +02001354
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001355static void alc_ssid_check(struct hda_codec *codec,
1356 hda_nid_t porta, hda_nid_t porte, hda_nid_t portd)
1357{
1358 if (!alc_subsystem_id(codec, porta, porte, portd)) {
1359 struct alc_spec *spec = codec->spec;
1360 snd_printd("realtek: "
1361 "Enable default setup for auto mode as fallback\n");
1362 spec->init_amp = ALC_INIT_DEFAULT;
1363 alc_init_auto_hp(codec);
Takashi Iwai6c819492009-08-10 18:47:44 +02001364 alc_init_auto_mic(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001365 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001366}
1367
Takashi Iwai41e41f12005-06-08 14:48:49 +02001368/*
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001369 * Fix-up pin default configurations and add default verbs
Takashi Iwaif95474e2007-07-10 00:47:43 +02001370 */
1371
1372struct alc_pincfg {
1373 hda_nid_t nid;
1374 u32 val;
1375};
1376
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001377struct alc_fixup {
1378 const struct alc_pincfg *pins;
1379 const struct hda_verb *verbs;
1380};
1381
1382static void alc_pick_fixup(struct hda_codec *codec,
Takashi Iwaif95474e2007-07-10 00:47:43 +02001383 const struct snd_pci_quirk *quirk,
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001384 const struct alc_fixup *fix)
Takashi Iwaif95474e2007-07-10 00:47:43 +02001385{
1386 const struct alc_pincfg *cfg;
1387
1388 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
1389 if (!quirk)
1390 return;
1391
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001392 fix += quirk->value;
1393 cfg = fix->pins;
1394 if (cfg) {
1395 for (; cfg->nid; cfg++)
1396 snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
1397 }
1398 if (fix->verbs)
1399 add_verb(codec->spec, fix->verbs);
Takashi Iwaif95474e2007-07-10 00:47:43 +02001400}
1401
Kailang Yang274693f2009-12-03 10:07:50 +01001402static int alc_read_coef_idx(struct hda_codec *codec,
1403 unsigned int coef_idx)
1404{
1405 unsigned int val;
1406 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
1407 coef_idx);
1408 val = snd_hda_codec_read(codec, 0x20, 0,
1409 AC_VERB_GET_PROC_COEF, 0);
1410 return val;
1411}
1412
Takashi Iwaif95474e2007-07-10 00:47:43 +02001413/*
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001414 * ALC888
1415 */
1416
1417/*
1418 * 2ch mode
1419 */
1420static struct hda_verb alc888_4ST_ch2_intel_init[] = {
1421/* Mic-in jack as mic in */
1422 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1423 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1424/* Line-in jack as Line in */
1425 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1426 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1427/* Line-Out as Front */
1428 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
1429 { } /* end */
1430};
1431
1432/*
1433 * 4ch mode
1434 */
1435static struct hda_verb alc888_4ST_ch4_intel_init[] = {
1436/* Mic-in jack as mic in */
1437 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1438 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1439/* Line-in jack as Surround */
1440 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1441 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1442/* Line-Out as Front */
1443 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
1444 { } /* end */
1445};
1446
1447/*
1448 * 6ch mode
1449 */
1450static struct hda_verb alc888_4ST_ch6_intel_init[] = {
1451/* Mic-in jack as CLFE */
1452 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1453 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1454/* Line-in jack as Surround */
1455 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1456 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1457/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */
1458 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1459 { } /* end */
1460};
1461
1462/*
1463 * 8ch mode
1464 */
1465static struct hda_verb alc888_4ST_ch8_intel_init[] = {
1466/* Mic-in jack as CLFE */
1467 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1468 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1469/* Line-in jack as Surround */
1470 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1471 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1472/* Line-Out as Side */
1473 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1474 { } /* end */
1475};
1476
1477static struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
1478 { 2, alc888_4ST_ch2_intel_init },
1479 { 4, alc888_4ST_ch4_intel_init },
1480 { 6, alc888_4ST_ch6_intel_init },
1481 { 8, alc888_4ST_ch8_intel_init },
1482};
1483
1484/*
1485 * ALC888 Fujitsu Siemens Amillo xa3530
1486 */
1487
1488static struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
1489/* Front Mic: set to PIN_IN (empty by default) */
1490 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1491/* Connect Internal HP to Front */
1492 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1493 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1494 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1495/* Connect Bass HP to Front */
1496 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1497 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1498 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1499/* Connect Line-Out side jack (SPDIF) to Side */
1500 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1501 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1502 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1503/* Connect Mic jack to CLFE */
1504 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1505 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1506 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
1507/* Connect Line-in jack to Surround */
1508 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1509 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1510 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
1511/* Connect HP out jack to Front */
1512 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1513 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1514 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
1515/* Enable unsolicited event for HP jack and Line-out jack */
1516 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1517 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1518 {}
1519};
1520
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001521static void alc_automute_amp(struct hda_codec *codec)
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001522{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001523 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +08001524 unsigned int mute;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001525 hda_nid_t nid;
1526 int i;
1527
1528 spec->jack_present = 0;
1529 for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
1530 nid = spec->autocfg.hp_pins[i];
1531 if (!nid)
1532 break;
Wu Fengguang864f92b2009-11-18 12:38:02 +08001533 if (snd_hda_jack_detect(codec, nid)) {
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001534 spec->jack_present = 1;
1535 break;
1536 }
1537 }
1538
1539 mute = spec->jack_present ? HDA_AMP_MUTE : 0;
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001540 /* Toggle internal speakers muting */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001541 for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
1542 nid = spec->autocfg.speaker_pins[i];
1543 if (!nid)
1544 break;
1545 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
1546 HDA_AMP_MUTE, mute);
1547 }
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001548}
1549
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001550static void alc_automute_amp_unsol_event(struct hda_codec *codec,
1551 unsigned int res)
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001552{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001553 if (codec->vendor_id == 0x10ec0880)
1554 res >>= 28;
1555 else
1556 res >>= 26;
1557 if (res == ALC880_HP_EVENT)
1558 alc_automute_amp(codec);
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001559}
1560
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001561static void alc889_automute_setup(struct hda_codec *codec)
Wu Fengguang6732bd02009-07-30 09:19:14 +02001562{
1563 struct alc_spec *spec = codec->spec;
1564
1565 spec->autocfg.hp_pins[0] = 0x15;
1566 spec->autocfg.speaker_pins[0] = 0x14;
1567 spec->autocfg.speaker_pins[1] = 0x16;
1568 spec->autocfg.speaker_pins[2] = 0x17;
1569 spec->autocfg.speaker_pins[3] = 0x19;
1570 spec->autocfg.speaker_pins[4] = 0x1a;
Wu Fengguang6732bd02009-07-30 09:19:14 +02001571}
1572
1573static void alc889_intel_init_hook(struct hda_codec *codec)
1574{
1575 alc889_coef_init(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001576 alc_automute_amp(codec);
Wu Fengguang6732bd02009-07-30 09:19:14 +02001577}
1578
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001579static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001580{
1581 struct alc_spec *spec = codec->spec;
1582
1583 spec->autocfg.hp_pins[0] = 0x17; /* line-out */
1584 spec->autocfg.hp_pins[1] = 0x1b; /* hp */
1585 spec->autocfg.speaker_pins[0] = 0x14; /* speaker */
1586 spec->autocfg.speaker_pins[1] = 0x15; /* bass */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001587}
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001588
1589/*
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001590 * ALC888 Acer Aspire 4930G model
1591 */
1592
1593static struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
1594/* Front Mic: set to PIN_IN (empty by default) */
1595 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1596/* Unselect Front Mic by default in input mixer 3 */
1597 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001598/* Enable unsolicited event for HP jack */
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001599 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1600/* Connect Internal HP to front */
1601 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1602 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1603 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1604/* Connect HP out to front */
1605 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1606 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1607 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1608 { }
1609};
1610
Hector Martin3b315d72009-06-02 10:54:19 +02001611/*
Tony Vroond2fd4b02009-06-21 00:40:10 +01001612 * ALC888 Acer Aspire 6530G model
1613 */
1614
1615static struct hda_verb alc888_acer_aspire_6530g_verbs[] = {
1616/* Bias voltage on for external mic port */
1617 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
Emilio López320d5922009-06-25 08:18:44 +02001618/* Front Mic: set to PIN_IN (empty by default) */
1619 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1620/* Unselect Front Mic by default in input mixer 3 */
1621 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Tony Vroond2fd4b02009-06-21 00:40:10 +01001622/* Enable unsolicited event for HP jack */
1623 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1624/* Enable speaker output */
1625 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1626 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1627/* Enable headphone output */
1628 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
1629 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1630 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1631 { }
1632};
1633
1634/*
Hector Martin018df412009-06-04 00:13:40 +02001635 * ALC889 Acer Aspire 8930G model
Hector Martin3b315d72009-06-02 10:54:19 +02001636 */
1637
Hector Martin018df412009-06-04 00:13:40 +02001638static struct hda_verb alc889_acer_aspire_8930g_verbs[] = {
Hector Martin3b315d72009-06-02 10:54:19 +02001639/* Front Mic: set to PIN_IN (empty by default) */
1640 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1641/* Unselect Front Mic by default in input mixer 3 */
1642 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
1643/* Enable unsolicited event for HP jack */
1644 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1645/* Connect Internal Front to Front */
1646 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1647 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1648 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1649/* Connect Internal Rear to Rear */
1650 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1651 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1652 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
1653/* Connect Internal CLFE to CLFE */
1654 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1655 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1656 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
1657/* Connect HP out to Front */
Hector Martin018df412009-06-04 00:13:40 +02001658 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
Hector Martin3b315d72009-06-02 10:54:19 +02001659 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1660 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1661/* Enable all DACs */
1662/* DAC DISABLE/MUTE 1? */
1663/* setting bits 1-5 disables DAC nids 0x02-0x06 apparently. Init=0x38 */
1664 {0x20, AC_VERB_SET_COEF_INDEX, 0x03},
1665 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
1666/* DAC DISABLE/MUTE 2? */
1667/* some bit here disables the other DACs. Init=0x4900 */
1668 {0x20, AC_VERB_SET_COEF_INDEX, 0x08},
1669 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
Hector Martin018df412009-06-04 00:13:40 +02001670/* DMIC fix
1671 * This laptop has a stereo digital microphone. The mics are only 1cm apart
1672 * which makes the stereo useless. However, either the mic or the ALC889
1673 * makes the signal become a difference/sum signal instead of standard
1674 * stereo, which is annoying. So instead we flip this bit which makes the
1675 * codec replicate the sum signal to both channels, turning it into a
1676 * normal mono mic.
1677 */
1678/* DMIC_CONTROL? Init value = 0x0001 */
1679 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
1680 {0x20, AC_VERB_SET_PROC_COEF, 0x0003},
Hector Martin3b315d72009-06-02 10:54:19 +02001681 { }
1682};
1683
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001684static struct hda_input_mux alc888_2_capture_sources[2] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001685 /* Front mic only available on one ADC */
1686 {
1687 .num_items = 4,
1688 .items = {
1689 { "Mic", 0x0 },
1690 { "Line", 0x2 },
1691 { "CD", 0x4 },
1692 { "Front Mic", 0xb },
1693 },
1694 },
1695 {
1696 .num_items = 3,
1697 .items = {
1698 { "Mic", 0x0 },
1699 { "Line", 0x2 },
1700 { "CD", 0x4 },
1701 },
1702 }
1703};
1704
Tony Vroond2fd4b02009-06-21 00:40:10 +01001705static struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
1706 /* Interal mic only available on one ADC */
1707 {
Tony Vroon684a8842009-06-26 09:27:50 +01001708 .num_items = 5,
Tony Vroond2fd4b02009-06-21 00:40:10 +01001709 .items = {
1710 { "Ext Mic", 0x0 },
Tony Vroon684a8842009-06-26 09:27:50 +01001711 { "Line In", 0x2 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01001712 { "CD", 0x4 },
Tony Vroon684a8842009-06-26 09:27:50 +01001713 { "Input Mix", 0xa },
Tony Vroond2fd4b02009-06-21 00:40:10 +01001714 { "Int Mic", 0xb },
1715 },
1716 },
1717 {
Tony Vroon684a8842009-06-26 09:27:50 +01001718 .num_items = 4,
Tony Vroond2fd4b02009-06-21 00:40:10 +01001719 .items = {
1720 { "Ext Mic", 0x0 },
Tony Vroon684a8842009-06-26 09:27:50 +01001721 { "Line In", 0x2 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01001722 { "CD", 0x4 },
Tony Vroon684a8842009-06-26 09:27:50 +01001723 { "Input Mix", 0xa },
Tony Vroond2fd4b02009-06-21 00:40:10 +01001724 },
1725 }
1726};
1727
Hector Martin018df412009-06-04 00:13:40 +02001728static struct hda_input_mux alc889_capture_sources[3] = {
1729 /* Digital mic only available on first "ADC" */
1730 {
1731 .num_items = 5,
1732 .items = {
1733 { "Mic", 0x0 },
1734 { "Line", 0x2 },
1735 { "CD", 0x4 },
1736 { "Front Mic", 0xb },
1737 { "Input Mix", 0xa },
1738 },
1739 },
1740 {
1741 .num_items = 4,
1742 .items = {
1743 { "Mic", 0x0 },
1744 { "Line", 0x2 },
1745 { "CD", 0x4 },
1746 { "Input Mix", 0xa },
1747 },
1748 },
1749 {
1750 .num_items = 4,
1751 .items = {
1752 { "Mic", 0x0 },
1753 { "Line", 0x2 },
1754 { "CD", 0x4 },
1755 { "Input Mix", 0xa },
1756 },
1757 }
1758};
1759
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001760static struct snd_kcontrol_new alc888_base_mixer[] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001761 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1762 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
1763 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1764 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
1765 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
1766 HDA_OUTPUT),
1767 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1768 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1769 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1770 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
1771 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
1772 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1773 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1774 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1775 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1776 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1777 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
1778 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001779 { } /* end */
1780};
1781
Hector Martin556eea92009-12-20 22:51:23 +01001782static struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = {
1783 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1784 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
1785 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1786 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
1787 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
1788 HDA_OUTPUT),
1789 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1790 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1791 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1792 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1793 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1794 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1795 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
1796 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1797 { } /* end */
1798};
1799
1800
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001801static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec)
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001802{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001803 struct alc_spec *spec = codec->spec;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001804
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001805 spec->autocfg.hp_pins[0] = 0x15;
1806 spec->autocfg.speaker_pins[0] = 0x14;
Łukasz Wojniłowicz7cef4cf2009-11-20 12:14:35 +01001807 spec->autocfg.speaker_pins[1] = 0x16;
1808 spec->autocfg.speaker_pins[2] = 0x17;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001809}
1810
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001811static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec)
Emilio López320d5922009-06-25 08:18:44 +02001812{
1813 struct alc_spec *spec = codec->spec;
1814
1815 spec->autocfg.hp_pins[0] = 0x15;
1816 spec->autocfg.speaker_pins[0] = 0x14;
1817 spec->autocfg.speaker_pins[1] = 0x16;
1818 spec->autocfg.speaker_pins[2] = 0x17;
Emilio López320d5922009-06-25 08:18:44 +02001819}
1820
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001821static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
Hector Martin3b315d72009-06-02 10:54:19 +02001822{
1823 struct alc_spec *spec = codec->spec;
1824
1825 spec->autocfg.hp_pins[0] = 0x15;
1826 spec->autocfg.speaker_pins[0] = 0x14;
1827 spec->autocfg.speaker_pins[1] = 0x16;
1828 spec->autocfg.speaker_pins[2] = 0x1b;
Hector Martin3b315d72009-06-02 10:54:19 +02001829}
1830
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001831/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001832 * ALC880 3-stack model
1833 *
1834 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001835 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
1836 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 */
1838
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001839static hda_nid_t alc880_dac_nids[4] = {
1840 /* front, rear, clfe, rear_surr */
1841 0x02, 0x05, 0x04, 0x03
1842};
1843
1844static hda_nid_t alc880_adc_nids[3] = {
1845 /* ADC0-2 */
1846 0x07, 0x08, 0x09,
1847};
1848
1849/* The datasheet says the node 0x07 is connected from inputs,
1850 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +01001851 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001853static hda_nid_t alc880_adc_nids_alt[2] = {
1854 /* ADC1-2 */
1855 0x08, 0x09,
1856};
1857
1858#define ALC880_DIGOUT_NID 0x06
1859#define ALC880_DIGIN_NID 0x0a
1860
1861static struct hda_input_mux alc880_capture_source = {
1862 .num_items = 4,
1863 .items = {
1864 { "Mic", 0x0 },
1865 { "Front Mic", 0x3 },
1866 { "Line", 0x2 },
1867 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001869};
1870
1871/* channel source setting (2/6 channel selection for 3-stack) */
1872/* 2ch mode */
1873static struct hda_verb alc880_threestack_ch2_init[] = {
1874 /* set line-in to input, mute it */
1875 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1876 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1877 /* set mic-in to input vref 80%, mute it */
1878 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1879 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 { } /* end */
1881};
1882
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001883/* 6ch mode */
1884static struct hda_verb alc880_threestack_ch6_init[] = {
1885 /* set line-in to output, unmute it */
1886 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1887 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1888 /* set mic-in to output, unmute it */
1889 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1890 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1891 { } /* end */
1892};
1893
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001894static struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001895 { 2, alc880_threestack_ch2_init },
1896 { 6, alc880_threestack_ch6_init },
1897};
1898
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001899static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001900 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001901 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001902 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001903 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001904 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1905 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001906 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1907 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1909 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1910 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1911 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1912 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1913 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1914 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
1915 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001917 {
1918 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1919 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001920 .info = alc_ch_mode_info,
1921 .get = alc_ch_mode_get,
1922 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001923 },
1924 { } /* end */
1925};
1926
1927/* capture mixer elements */
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001928static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
1929 struct snd_ctl_elem_info *uinfo)
1930{
1931 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1932 struct alc_spec *spec = codec->spec;
1933 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001934
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001935 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001936 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
1937 HDA_INPUT);
1938 err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001939 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001940 return err;
1941}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001943static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
1944 unsigned int size, unsigned int __user *tlv)
1945{
1946 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1947 struct alc_spec *spec = codec->spec;
1948 int err;
1949
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001950 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001951 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
1952 HDA_INPUT);
1953 err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001954 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001955 return err;
1956}
1957
1958typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
1959 struct snd_ctl_elem_value *ucontrol);
1960
1961static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
1962 struct snd_ctl_elem_value *ucontrol,
1963 getput_call_t func)
1964{
1965 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1966 struct alc_spec *spec = codec->spec;
1967 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1968 int err;
1969
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001970 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001971 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[adc_idx],
1972 3, 0, HDA_INPUT);
1973 err = func(kcontrol, ucontrol);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001974 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001975 return err;
1976}
1977
1978static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
1979 struct snd_ctl_elem_value *ucontrol)
1980{
1981 return alc_cap_getput_caller(kcontrol, ucontrol,
1982 snd_hda_mixer_amp_volume_get);
1983}
1984
1985static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
1986 struct snd_ctl_elem_value *ucontrol)
1987{
1988 return alc_cap_getput_caller(kcontrol, ucontrol,
1989 snd_hda_mixer_amp_volume_put);
1990}
1991
1992/* capture mixer elements */
1993#define alc_cap_sw_info snd_ctl_boolean_stereo_info
1994
1995static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
1996 struct snd_ctl_elem_value *ucontrol)
1997{
1998 return alc_cap_getput_caller(kcontrol, ucontrol,
1999 snd_hda_mixer_amp_switch_get);
2000}
2001
2002static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
2003 struct snd_ctl_elem_value *ucontrol)
2004{
2005 return alc_cap_getput_caller(kcontrol, ucontrol,
2006 snd_hda_mixer_amp_switch_put);
2007}
2008
Takashi Iwaia23b6882009-03-23 15:21:36 +01002009#define _DEFINE_CAPMIX(num) \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002010 { \
2011 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2012 .name = "Capture Switch", \
2013 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
2014 .count = num, \
2015 .info = alc_cap_sw_info, \
2016 .get = alc_cap_sw_get, \
2017 .put = alc_cap_sw_put, \
2018 }, \
2019 { \
2020 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2021 .name = "Capture Volume", \
2022 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
2023 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
2024 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
2025 .count = num, \
2026 .info = alc_cap_vol_info, \
2027 .get = alc_cap_vol_get, \
2028 .put = alc_cap_vol_put, \
2029 .tlv = { .c = alc_cap_vol_tlv }, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002030 }
2031
2032#define _DEFINE_CAPSRC(num) \
Takashi Iwai3c3e9892008-10-31 17:48:56 +01002033 { \
2034 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2035 /* .name = "Capture Source", */ \
2036 .name = "Input Source", \
2037 .count = num, \
2038 .info = alc_mux_enum_info, \
2039 .get = alc_mux_enum_get, \
2040 .put = alc_mux_enum_put, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002041 }
2042
2043#define DEFINE_CAPMIX(num) \
2044static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
2045 _DEFINE_CAPMIX(num), \
2046 _DEFINE_CAPSRC(num), \
2047 { } /* end */ \
2048}
2049
2050#define DEFINE_CAPMIX_NOSRC(num) \
2051static struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
2052 _DEFINE_CAPMIX(num), \
2053 { } /* end */ \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002054}
2055
2056/* up to three ADCs */
2057DEFINE_CAPMIX(1);
2058DEFINE_CAPMIX(2);
2059DEFINE_CAPMIX(3);
Takashi Iwaia23b6882009-03-23 15:21:36 +01002060DEFINE_CAPMIX_NOSRC(1);
2061DEFINE_CAPMIX_NOSRC(2);
2062DEFINE_CAPMIX_NOSRC(3);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002063
2064/*
2065 * ALC880 5-stack model
2066 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002067 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
2068 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002069 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
2070 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
2071 */
2072
2073/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002074static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002075 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002076 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077 { } /* end */
2078};
2079
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002080/* channel source setting (6/8 channel selection for 5-stack) */
2081/* 6ch mode */
2082static struct hda_verb alc880_fivestack_ch6_init[] = {
2083 /* set line-in to input, mute it */
2084 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2085 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002086 { } /* end */
2087};
2088
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002089/* 8ch mode */
2090static struct hda_verb alc880_fivestack_ch8_init[] = {
2091 /* set line-in to output, unmute it */
2092 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2093 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2094 { } /* end */
2095};
2096
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002097static struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002098 { 6, alc880_fivestack_ch6_init },
2099 { 8, alc880_fivestack_ch8_init },
2100};
2101
2102
2103/*
2104 * ALC880 6-stack model
2105 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002106 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
2107 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002108 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
2109 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
2110 */
2111
2112static hda_nid_t alc880_6st_dac_nids[4] = {
2113 /* front, rear, clfe, rear_surr */
2114 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002115};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002116
2117static struct hda_input_mux alc880_6stack_capture_source = {
2118 .num_items = 4,
2119 .items = {
2120 { "Mic", 0x0 },
2121 { "Front Mic", 0x1 },
2122 { "Line", 0x2 },
2123 { "CD", 0x4 },
2124 },
2125};
2126
2127/* fixed 8-channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002128static struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002129 { 8, NULL },
2130};
2131
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002132static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002133 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002134 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002135 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002136 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002137 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2138 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002139 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2140 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002141 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002142 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002143 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2144 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2145 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2146 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2147 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2148 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2149 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2150 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002151 {
2152 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2153 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002154 .info = alc_ch_mode_info,
2155 .get = alc_ch_mode_get,
2156 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02002157 },
2158 { } /* end */
2159};
2160
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002161
2162/*
2163 * ALC880 W810 model
2164 *
2165 * W810 has rear IO for:
2166 * Front (DAC 02)
2167 * Surround (DAC 03)
2168 * Center/LFE (DAC 04)
2169 * Digital out (06)
2170 *
2171 * The system also has a pair of internal speakers, and a headphone jack.
2172 * These are both connected to Line2 on the codec, hence to DAC 02.
Kailang Yangea1fb292008-08-26 12:58:38 +02002173 *
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002174 * There is a variable resistor to control the speaker or headphone
2175 * volume. This is a hardware-only device without a software API.
2176 *
2177 * Plugging headphones in will disable the internal speakers. This is
2178 * implemented in hardware, not via the driver using jack sense. In
2179 * a similar fashion, plugging into the rear socket marked "front" will
2180 * disable both the speakers and headphones.
2181 *
2182 * For input, there's a microphone jack, and an "audio in" jack.
2183 * These may not do anything useful with this driver yet, because I
2184 * haven't setup any initialization verbs for these yet...
2185 */
2186
2187static hda_nid_t alc880_w810_dac_nids[3] = {
2188 /* front, rear/surround, clfe */
2189 0x02, 0x03, 0x04
2190};
2191
2192/* fixed 6 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002193static struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002194 { 6, NULL }
2195};
2196
2197/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002198static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002199 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002200 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002201 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002202 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002203 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2204 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002205 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2206 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002207 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
2208 { } /* end */
2209};
2210
2211
2212/*
2213 * Z710V model
2214 *
2215 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002216 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
2217 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002218 */
2219
2220static hda_nid_t alc880_z71v_dac_nids[1] = {
2221 0x02
2222};
2223#define ALC880_Z71V_HP_DAC 0x03
2224
2225/* fixed 2 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002226static struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002227 { 2, NULL }
2228};
2229
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002230static struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002231 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002232 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002233 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002234 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002235 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2236 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2237 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2238 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2239 { } /* end */
2240};
2241
2242
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002243/*
2244 * ALC880 F1734 model
2245 *
2246 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
2247 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
2248 */
2249
2250static hda_nid_t alc880_f1734_dac_nids[1] = {
2251 0x03
2252};
2253#define ALC880_F1734_HP_DAC 0x02
2254
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002255static struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002256 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002257 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01002258 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2259 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002260 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2261 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01002262 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2263 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002264 { } /* end */
2265};
2266
Takashi Iwai937b4162008-02-11 14:52:36 +01002267static struct hda_input_mux alc880_f1734_capture_source = {
2268 .num_items = 2,
2269 .items = {
2270 { "Mic", 0x1 },
2271 { "CD", 0x4 },
2272 },
2273};
2274
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002275
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002276/*
2277 * ALC880 ASUS model
2278 *
2279 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
2280 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
2281 * Mic = 0x18, Line = 0x1a
2282 */
2283
2284#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
2285#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
2286
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002287static struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002288 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002289 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002290 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002291 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002292 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2293 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002294 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2295 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002296 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2297 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2298 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2299 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2300 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2301 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002302 {
2303 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2304 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002305 .info = alc_ch_mode_info,
2306 .get = alc_ch_mode_get,
2307 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02002308 },
2309 { } /* end */
2310};
2311
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002312/*
2313 * ALC880 ASUS W1V model
2314 *
2315 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
2316 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
2317 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
2318 */
2319
2320/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002321static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002322 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
2323 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002324 { } /* end */
2325};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002326
Kailang Yangdf694da2005-12-05 19:42:22 +01002327/* TCL S700 */
2328static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
2329 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2330 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
2331 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
2332 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
2333 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
2334 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
2335 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
2336 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
2337 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01002338 { } /* end */
2339};
2340
Kailang Yangccc656c2006-10-17 12:32:26 +02002341/* Uniwill */
2342static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002343 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2344 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2345 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2346 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002347 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2348 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2349 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2350 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2351 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2352 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2353 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2354 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2355 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2356 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2357 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2358 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002359 {
2360 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2361 .name = "Channel Mode",
2362 .info = alc_ch_mode_info,
2363 .get = alc_ch_mode_get,
2364 .put = alc_ch_mode_put,
2365 },
2366 { } /* end */
2367};
2368
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002369static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
2370 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2371 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2372 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2373 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
2374 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2375 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2376 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2377 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2378 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2379 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
2380 { } /* end */
2381};
2382
Kailang Yangccc656c2006-10-17 12:32:26 +02002383static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002384 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2385 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2386 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2387 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002388 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2389 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2390 { } /* end */
2391};
2392
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01002394 * virtual master controls
2395 */
2396
2397/*
2398 * slave controls for virtual master
2399 */
2400static const char *alc_slave_vols[] = {
2401 "Front Playback Volume",
2402 "Surround Playback Volume",
2403 "Center Playback Volume",
2404 "LFE Playback Volume",
2405 "Side Playback Volume",
2406 "Headphone Playback Volume",
2407 "Speaker Playback Volume",
2408 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002409 "Line-Out Playback Volume",
Takashi Iwai26f5df22008-11-03 17:39:46 +01002410 "PCM Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002411 NULL,
2412};
2413
2414static const char *alc_slave_sws[] = {
2415 "Front Playback Switch",
2416 "Surround Playback Switch",
2417 "Center Playback Switch",
2418 "LFE Playback Switch",
2419 "Side Playback Switch",
2420 "Headphone Playback Switch",
2421 "Speaker Playback Switch",
2422 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01002423 "IEC958 Playback Switch",
Takashi Iwai23033b22009-12-08 12:36:52 +01002424 "Line-Out Playback Switch",
2425 "PCM Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002426 NULL,
2427};
2428
2429/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002430 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431 */
Takashi Iwai603c4012008-07-30 15:01:44 +02002432
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002433#define NID_MAPPING (-1)
2434
2435#define SUBDEV_SPEAKER_ (0 << 6)
2436#define SUBDEV_HP_ (1 << 6)
2437#define SUBDEV_LINE_ (2 << 6)
2438#define SUBDEV_SPEAKER(x) (SUBDEV_SPEAKER_ | ((x) & 0x3f))
2439#define SUBDEV_HP(x) (SUBDEV_HP_ | ((x) & 0x3f))
2440#define SUBDEV_LINE(x) (SUBDEV_LINE_ | ((x) & 0x3f))
2441
Takashi Iwai603c4012008-07-30 15:01:44 +02002442static void alc_free_kctls(struct hda_codec *codec);
2443
Takashi Iwai67d634c2009-11-16 15:35:59 +01002444#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002445/* additional beep mixers; the actual parameters are overwritten at build */
2446static struct snd_kcontrol_new alc_beep_mixer[] = {
2447 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
Jaroslav Kysela123c07a2009-10-21 14:48:23 +02002448 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002449 { } /* end */
2450};
Takashi Iwai67d634c2009-11-16 15:35:59 +01002451#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002452
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453static int alc_build_controls(struct hda_codec *codec)
2454{
2455 struct alc_spec *spec = codec->spec;
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002456 struct snd_kcontrol *kctl;
2457 struct snd_kcontrol_new *knew;
2458 int i, j, err;
2459 unsigned int u;
2460 hda_nid_t nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461
2462 for (i = 0; i < spec->num_mixers; i++) {
2463 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
2464 if (err < 0)
2465 return err;
2466 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002467 if (spec->cap_mixer) {
2468 err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
2469 if (err < 0)
2470 return err;
2471 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002473 err = snd_hda_create_spdif_out_ctls(codec,
2474 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 if (err < 0)
2476 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002477 if (!spec->no_analog) {
2478 err = snd_hda_create_spdif_share_sw(codec,
2479 &spec->multiout);
2480 if (err < 0)
2481 return err;
2482 spec->multiout.share_spdif = 1;
2483 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 }
2485 if (spec->dig_in_nid) {
2486 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
2487 if (err < 0)
2488 return err;
2489 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01002490
Takashi Iwai67d634c2009-11-16 15:35:59 +01002491#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002492 /* create beep controls if needed */
2493 if (spec->beep_amp) {
2494 struct snd_kcontrol_new *knew;
2495 for (knew = alc_beep_mixer; knew->name; knew++) {
2496 struct snd_kcontrol *kctl;
2497 kctl = snd_ctl_new1(knew, codec);
2498 if (!kctl)
2499 return -ENOMEM;
2500 kctl->private_value = spec->beep_amp;
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01002501 err = snd_hda_ctl_add(codec, 0, kctl);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002502 if (err < 0)
2503 return err;
2504 }
2505 }
Takashi Iwai67d634c2009-11-16 15:35:59 +01002506#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002507
Takashi Iwai2134ea42008-01-10 16:53:55 +01002508 /* if we have no master control, let's create it */
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002509 if (!spec->no_analog &&
2510 !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002511 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01002512 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002513 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01002514 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002515 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01002516 if (err < 0)
2517 return err;
2518 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002519 if (!spec->no_analog &&
2520 !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002521 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
2522 NULL, alc_slave_sws);
2523 if (err < 0)
2524 return err;
2525 }
2526
Takashi Iwai603c4012008-07-30 15:01:44 +02002527 alc_free_kctls(codec); /* no longer needed */
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002528
2529 /* assign Capture Source enums to NID */
2530 kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
2531 if (!kctl)
2532 kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
2533 for (i = 0; kctl && i < kctl->count; i++) {
Takashi Iwaid1409ae2009-12-17 15:01:31 +01002534 hda_nid_t *nids = spec->capsrc_nids;
2535 if (!nids)
2536 nids = spec->adc_nids;
Takashi Iwai21949f02009-12-23 08:31:59 +01002537 err = snd_hda_add_nid(codec, kctl, i, nids[i]);
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002538 if (err < 0)
2539 return err;
2540 }
2541 if (spec->cap_mixer) {
2542 const char *kname = kctl ? kctl->id.name : NULL;
2543 for (knew = spec->cap_mixer; knew->name; knew++) {
2544 if (kname && strcmp(knew->name, kname) == 0)
2545 continue;
2546 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
2547 for (i = 0; kctl && i < kctl->count; i++) {
2548 err = snd_hda_add_nid(codec, kctl, i,
2549 spec->adc_nids[i]);
2550 if (err < 0)
2551 return err;
2552 }
2553 }
2554 }
2555
2556 /* other nid->control mapping */
2557 for (i = 0; i < spec->num_mixers; i++) {
2558 for (knew = spec->mixers[i]; knew->name; knew++) {
2559 if (knew->iface != NID_MAPPING)
2560 continue;
2561 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
2562 if (kctl == NULL)
2563 continue;
2564 u = knew->subdevice;
2565 for (j = 0; j < 4; j++, u >>= 8) {
2566 nid = u & 0x3f;
2567 if (nid == 0)
2568 continue;
2569 switch (u & 0xc0) {
2570 case SUBDEV_SPEAKER_:
2571 nid = spec->autocfg.speaker_pins[nid];
2572 break;
2573 case SUBDEV_LINE_:
2574 nid = spec->autocfg.line_out_pins[nid];
2575 break;
2576 case SUBDEV_HP_:
2577 nid = spec->autocfg.hp_pins[nid];
2578 break;
2579 default:
2580 continue;
2581 }
2582 err = snd_hda_add_nid(codec, kctl, 0, nid);
2583 if (err < 0)
2584 return err;
2585 }
2586 u = knew->private_value;
2587 for (j = 0; j < 4; j++, u >>= 8) {
2588 nid = u & 0xff;
2589 if (nid == 0)
2590 continue;
2591 err = snd_hda_add_nid(codec, kctl, 0, nid);
2592 if (err < 0)
2593 return err;
2594 }
2595 }
2596 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 return 0;
2598}
2599
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002600
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601/*
2602 * initialize the codec volumes, etc
2603 */
2604
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002605/*
2606 * generic initialization of ADC, input mixers and output mixers
2607 */
2608static struct hda_verb alc880_volume_init_verbs[] = {
2609 /*
2610 * Unmute ADC0-2 and set the default input to mic-in
2611 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002612 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002613 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002614 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002615 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002616 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002617 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002619 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2620 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002621 * Note: PASD motherboards uses the Line In 2 as the input for front
2622 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002624 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02002625 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2626 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2627 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2628 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2629 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2630 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2631 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002633 /*
2634 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002636 /* set vol=0 to output mixers */
2637 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2638 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2639 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2640 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2641 /* set up input amps for analog loopback */
2642 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002643 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2644 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002645 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2646 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002647 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2648 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002649 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2650 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651
2652 { }
2653};
2654
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002655/*
2656 * 3-stack pin configuration:
2657 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
2658 */
2659static struct hda_verb alc880_pin_3stack_init_verbs[] = {
2660 /*
2661 * preset connection lists of input pins
2662 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
2663 */
2664 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
2665 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2666 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
2667
2668 /*
2669 * Set pin mode and muting
2670 */
2671 /* set front pin widgets 0x14 for output */
2672 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2673 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2674 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2675 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2676 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2677 /* Mic2 (as headphone out) for HP output */
2678 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2679 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2680 /* Line In pin widget for input */
2681 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2682 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2683 /* Line2 (as front mic) pin widget for input and vref at 80% */
2684 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2685 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2686 /* CD pin widget for input */
2687 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2688
2689 { }
2690};
2691
2692/*
2693 * 5-stack pin configuration:
2694 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
2695 * line-in/side = 0x1a, f-mic = 0x1b
2696 */
2697static struct hda_verb alc880_pin_5stack_init_verbs[] = {
2698 /*
2699 * preset connection lists of input pins
2700 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
2701 */
2702 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2703 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
2704
2705 /*
2706 * Set pin mode and muting
2707 */
2708 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02002709 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2710 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2711 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2712 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002713 /* unmute pins for output (no gain on this amp) */
2714 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2715 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2716 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2717 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2718
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02002720 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002721 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2722 /* Mic2 (as headphone out) for HP output */
2723 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02002724 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002725 /* Line In pin widget for input */
2726 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2727 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2728 /* Line2 (as front mic) pin widget for input and vref at 80% */
2729 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2730 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2731 /* CD pin widget for input */
2732 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733
2734 { }
2735};
2736
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002737/*
2738 * W810 pin configuration:
2739 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
2740 */
2741static struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 /* hphone/speaker input selector: front DAC */
2743 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
2744
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002745 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2746 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2747 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2748 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2749 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2750 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2751
2752 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02002753 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 { }
2756};
2757
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002758/*
2759 * Z71V pin configuration:
2760 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
2761 */
2762static struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002763 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002764 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02002765 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002766 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002767
Takashi Iwai16ded522005-06-10 19:58:24 +02002768 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002769 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02002770 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002771 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002772
2773 { }
2774};
2775
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002776/*
2777 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002778 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
2779 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002780 */
2781static struct hda_verb alc880_pin_6stack_init_verbs[] = {
2782 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2783
Takashi Iwai16ded522005-06-10 19:58:24 +02002784 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002785 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002786 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002787 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002788 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002789 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002790 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002791 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2792
Takashi Iwai16ded522005-06-10 19:58:24 +02002793 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002794 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002795 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002796 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002797 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002798 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002799 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02002800 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002801 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02002802
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002803 { }
2804};
Takashi Iwai16ded522005-06-10 19:58:24 +02002805
Kailang Yangccc656c2006-10-17 12:32:26 +02002806/*
2807 * Uniwill pin configuration:
2808 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
2809 * line = 0x1a
2810 */
2811static struct hda_verb alc880_uniwill_init_verbs[] = {
2812 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2813
2814 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2815 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2816 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2817 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2818 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2819 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2820 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2821 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2822 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2823 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2824 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2825 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2826 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2827 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2828
2829 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2830 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2831 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2832 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2833 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2834 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2835 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
2836 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
2837 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2838
2839 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2840 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
2841
2842 { }
2843};
2844
2845/*
2846* Uniwill P53
Kailang Yangea1fb292008-08-26 12:58:38 +02002847* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
Kailang Yangccc656c2006-10-17 12:32:26 +02002848 */
2849static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
2850 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2851
2852 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2853 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2854 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2855 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2856 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2857 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2858 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2859 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2860 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2861 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2862 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2863 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2864
2865 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2866 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2867 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2868 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2869 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2870 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2871
2872 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2873 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
2874
2875 { }
2876};
2877
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002878static struct hda_verb alc880_beep_init_verbs[] = {
2879 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
2880 { }
2881};
2882
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002883/* auto-toggle front mic */
2884static void alc880_uniwill_mic_automute(struct hda_codec *codec)
2885{
2886 unsigned int present;
2887 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02002888
Wu Fengguang864f92b2009-11-18 12:38:02 +08002889 present = snd_hda_jack_detect(codec, 0x18);
Takashi Iwai47fd8302007-08-10 17:11:07 +02002890 bits = present ? HDA_AMP_MUTE : 0;
2891 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002892}
2893
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002894static void alc880_uniwill_setup(struct hda_codec *codec)
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002895{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002896 struct alc_spec *spec = codec->spec;
2897
2898 spec->autocfg.hp_pins[0] = 0x14;
2899 spec->autocfg.speaker_pins[0] = 0x15;
2900 spec->autocfg.speaker_pins[0] = 0x16;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002901}
2902
2903static void alc880_uniwill_init_hook(struct hda_codec *codec)
2904{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002905 alc_automute_amp(codec);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002906 alc880_uniwill_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02002907}
2908
2909static void alc880_uniwill_unsol_event(struct hda_codec *codec,
2910 unsigned int res)
2911{
2912 /* Looks like the unsol event is incompatible with the standard
2913 * definition. 4bit tag is placed at 28 bit!
2914 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002915 switch (res >> 28) {
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002916 case ALC880_MIC_EVENT:
2917 alc880_uniwill_mic_automute(codec);
2918 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002919 default:
2920 alc_automute_amp_unsol_event(codec, res);
2921 break;
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002922 }
Kailang Yangccc656c2006-10-17 12:32:26 +02002923}
2924
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002925static void alc880_uniwill_p53_setup(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02002926{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002927 struct alc_spec *spec = codec->spec;
Kailang Yangccc656c2006-10-17 12:32:26 +02002928
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002929 spec->autocfg.hp_pins[0] = 0x14;
2930 spec->autocfg.speaker_pins[0] = 0x15;
Kailang Yangccc656c2006-10-17 12:32:26 +02002931}
2932
2933static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
2934{
2935 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02002936
Kailang Yangccc656c2006-10-17 12:32:26 +02002937 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02002938 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
2939 present &= HDA_AMP_VOLMASK;
2940 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
2941 HDA_AMP_VOLMASK, present);
2942 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
2943 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02002944}
Takashi Iwai47fd8302007-08-10 17:11:07 +02002945
Kailang Yangccc656c2006-10-17 12:32:26 +02002946static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
2947 unsigned int res)
2948{
2949 /* Looks like the unsol event is incompatible with the standard
2950 * definition. 4bit tag is placed at 28 bit!
2951 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002952 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02002953 alc880_uniwill_p53_dcvol_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002954 else
2955 alc_automute_amp_unsol_event(codec, res);
Kailang Yangccc656c2006-10-17 12:32:26 +02002956}
2957
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002958/*
2959 * F1734 pin configuration:
2960 * HP = 0x14, speaker-out = 0x15, mic = 0x18
2961 */
2962static struct hda_verb alc880_pin_f1734_init_verbs[] = {
Michael Gruberee7a9c72008-03-10 11:30:59 +01002963 {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002964 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
2965 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
2966 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
2967 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
2968
2969 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2970 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2971 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2972 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2973
2974 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2975 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Michael Gruberee7a9c72008-03-10 11:30:59 +01002976 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002977 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2978 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2979 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2980 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2981 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2982 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02002983
Takashi Iwai937b4162008-02-11 14:52:36 +01002984 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
2985 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
2986
Takashi Iwai16ded522005-06-10 19:58:24 +02002987 { }
2988};
2989
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002990/*
2991 * ASUS pin configuration:
2992 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
2993 */
2994static struct hda_verb alc880_pin_asus_init_verbs[] = {
2995 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
2996 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
2997 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
2998 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
2999
3000 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3001 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3002 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3003 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3004 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3005 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3006 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3007 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3008
3009 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3010 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3011 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3012 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3013 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3014 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3015 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3016 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3017 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02003018
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003019 { }
3020};
3021
3022/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003023#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
3024#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
David Heidelberger64a8be72009-06-08 16:15:18 +02003025#define alc880_gpio3_init_verbs alc_gpio3_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003026
Kailang Yangdf694da2005-12-05 19:42:22 +01003027/* Clevo m520g init */
3028static struct hda_verb alc880_pin_clevo_init_verbs[] = {
3029 /* headphone output */
3030 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3031 /* line-out */
3032 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3033 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3034 /* Line-in */
3035 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3036 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3037 /* CD */
3038 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3039 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3040 /* Mic1 (rear panel) */
3041 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3042 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3043 /* Mic2 (front panel) */
3044 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3045 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3046 /* headphone */
3047 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3048 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3049 /* change to EAPD mode */
3050 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3051 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3052
3053 { }
3054};
3055
3056static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02003057 /* change to EAPD mode */
3058 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3059 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3060
Kailang Yangdf694da2005-12-05 19:42:22 +01003061 /* Headphone output */
3062 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3063 /* Front output*/
3064 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3065 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
3066
3067 /* Line In pin widget for input */
3068 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3069 /* CD pin widget for input */
3070 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3071 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3072 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3073
3074 /* change to EAPD mode */
3075 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3076 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
3077
3078 { }
3079};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003080
3081/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003082 * LG m1 express dual
3083 *
3084 * Pin assignment:
3085 * Rear Line-In/Out (blue): 0x14
3086 * Build-in Mic-In: 0x15
3087 * Speaker-out: 0x17
3088 * HP-Out (green): 0x1b
3089 * Mic-In/Out (red): 0x19
3090 * SPDIF-Out: 0x1e
3091 */
3092
3093/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
3094static hda_nid_t alc880_lg_dac_nids[3] = {
3095 0x05, 0x02, 0x03
3096};
3097
3098/* seems analog CD is not working */
3099static struct hda_input_mux alc880_lg_capture_source = {
3100 .num_items = 3,
3101 .items = {
3102 { "Mic", 0x1 },
3103 { "Line", 0x5 },
3104 { "Internal Mic", 0x6 },
3105 },
3106};
3107
3108/* 2,4,6 channel modes */
3109static struct hda_verb alc880_lg_ch2_init[] = {
3110 /* set line-in and mic-in to input */
3111 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
3112 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3113 { }
3114};
3115
3116static struct hda_verb alc880_lg_ch4_init[] = {
3117 /* set line-in to out and mic-in to input */
3118 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3119 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3120 { }
3121};
3122
3123static struct hda_verb alc880_lg_ch6_init[] = {
3124 /* set line-in and mic-in to output */
3125 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3126 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3127 { }
3128};
3129
3130static struct hda_channel_mode alc880_lg_ch_modes[3] = {
3131 { 2, alc880_lg_ch2_init },
3132 { 4, alc880_lg_ch4_init },
3133 { 6, alc880_lg_ch6_init },
3134};
3135
3136static struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003137 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
3138 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003139 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3140 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
3141 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
3142 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
3143 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
3144 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
3145 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3146 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
3147 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
3148 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
3149 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
3150 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
3151 {
3152 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3153 .name = "Channel Mode",
3154 .info = alc_ch_mode_info,
3155 .get = alc_ch_mode_get,
3156 .put = alc_ch_mode_put,
3157 },
3158 { } /* end */
3159};
3160
3161static struct hda_verb alc880_lg_init_verbs[] = {
3162 /* set capture source to mic-in */
3163 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3164 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3165 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3166 /* mute all amp mixer inputs */
3167 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02003168 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
3169 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003170 /* line-in to input */
3171 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3172 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3173 /* built-in mic */
3174 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3175 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3176 /* speaker-out */
3177 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3178 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3179 /* mic-in to input */
3180 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3181 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3182 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3183 /* HP-out */
3184 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
3185 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3186 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3187 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003188 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003189 { }
3190};
3191
3192/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003193static void alc880_lg_setup(struct hda_codec *codec)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003194{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003195 struct alc_spec *spec = codec->spec;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003196
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003197 spec->autocfg.hp_pins[0] = 0x1b;
3198 spec->autocfg.speaker_pins[0] = 0x17;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003199}
3200
3201/*
Takashi Iwaid6815182006-03-23 16:06:23 +01003202 * LG LW20
3203 *
3204 * Pin assignment:
3205 * Speaker-out: 0x14
3206 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003207 * Built-in Mic-In: 0x19
3208 * Line-In: 0x1b
3209 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01003210 * SPDIF-Out: 0x1e
3211 */
3212
Takashi Iwaid6815182006-03-23 16:06:23 +01003213static struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003214 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01003215 .items = {
3216 { "Mic", 0x0 },
3217 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003218 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003219 },
3220};
3221
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003222#define alc880_lg_lw_modes alc880_threestack_modes
3223
Takashi Iwaid6815182006-03-23 16:06:23 +01003224static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003225 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3226 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
3227 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
3228 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
3229 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
3230 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
3231 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
3232 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
3233 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
3234 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01003235 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3236 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3237 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
3238 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003239 {
3240 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3241 .name = "Channel Mode",
3242 .info = alc_ch_mode_info,
3243 .get = alc_ch_mode_get,
3244 .put = alc_ch_mode_put,
3245 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003246 { } /* end */
3247};
3248
3249static struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003250 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3251 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
3252 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
3253
Takashi Iwaid6815182006-03-23 16:06:23 +01003254 /* set capture source to mic-in */
3255 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3256 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3257 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02003258 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01003259 /* speaker-out */
3260 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3261 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3262 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01003263 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3264 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3265 /* mic-in to input */
3266 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3267 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3268 /* built-in mic */
3269 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3270 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3271 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003272 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaid6815182006-03-23 16:06:23 +01003273 { }
3274};
3275
3276/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003277static void alc880_lg_lw_setup(struct hda_codec *codec)
Takashi Iwaid6815182006-03-23 16:06:23 +01003278{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003279 struct alc_spec *spec = codec->spec;
Takashi Iwaid6815182006-03-23 16:06:23 +01003280
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003281 spec->autocfg.hp_pins[0] = 0x1b;
3282 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid6815182006-03-23 16:06:23 +01003283}
3284
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003285static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
3286 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3287 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
3288 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3289 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3290 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3291 HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
3292 { } /* end */
3293};
3294
3295static struct hda_input_mux alc880_medion_rim_capture_source = {
3296 .num_items = 2,
3297 .items = {
3298 { "Mic", 0x0 },
3299 { "Internal Mic", 0x1 },
3300 },
3301};
3302
3303static struct hda_verb alc880_medion_rim_init_verbs[] = {
3304 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3305
3306 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3307 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3308
3309 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3310 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3311 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3312 /* Mic2 (as headphone out) for HP output */
3313 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3314 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3315 /* Internal Speaker */
3316 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3317 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3318
3319 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3320 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3321
3322 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3323 { }
3324};
3325
3326/* toggle speaker-output according to the hp-jack state */
3327static void alc880_medion_rim_automute(struct hda_codec *codec)
3328{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003329 struct alc_spec *spec = codec->spec;
3330 alc_automute_amp(codec);
3331 /* toggle EAPD */
3332 if (spec->jack_present)
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003333 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
3334 else
3335 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
3336}
3337
3338static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
3339 unsigned int res)
3340{
3341 /* Looks like the unsol event is incompatible with the standard
3342 * definition. 4bit tag is placed at 28 bit!
3343 */
3344 if ((res >> 28) == ALC880_HP_EVENT)
3345 alc880_medion_rim_automute(codec);
3346}
3347
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003348static void alc880_medion_rim_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003349{
3350 struct alc_spec *spec = codec->spec;
3351
3352 spec->autocfg.hp_pins[0] = 0x14;
3353 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003354}
3355
Takashi Iwaicb53c622007-08-10 17:21:45 +02003356#ifdef CONFIG_SND_HDA_POWER_SAVE
3357static struct hda_amp_list alc880_loopbacks[] = {
3358 { 0x0b, HDA_INPUT, 0 },
3359 { 0x0b, HDA_INPUT, 1 },
3360 { 0x0b, HDA_INPUT, 2 },
3361 { 0x0b, HDA_INPUT, 3 },
3362 { 0x0b, HDA_INPUT, 4 },
3363 { } /* end */
3364};
3365
3366static struct hda_amp_list alc880_lg_loopbacks[] = {
3367 { 0x0b, HDA_INPUT, 1 },
3368 { 0x0b, HDA_INPUT, 6 },
3369 { 0x0b, HDA_INPUT, 7 },
3370 { } /* end */
3371};
3372#endif
3373
Takashi Iwaid6815182006-03-23 16:06:23 +01003374/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003375 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003376 */
Takashi Iwai16ded522005-06-10 19:58:24 +02003377
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378static int alc_init(struct hda_codec *codec)
3379{
3380 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003381 unsigned int i;
3382
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02003383 alc_fix_pll(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02003384 alc_auto_init_amp(codec, spec->init_amp);
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02003385
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003386 for (i = 0; i < spec->num_init_verbs; i++)
3387 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003388
3389 if (spec->init_hook)
3390 spec->init_hook(codec);
3391
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392 return 0;
3393}
3394
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003395static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
3396{
3397 struct alc_spec *spec = codec->spec;
3398
3399 if (spec->unsol_event)
3400 spec->unsol_event(codec, res);
3401}
3402
Takashi Iwaicb53c622007-08-10 17:21:45 +02003403#ifdef CONFIG_SND_HDA_POWER_SAVE
3404static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
3405{
3406 struct alc_spec *spec = codec->spec;
3407 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
3408}
3409#endif
3410
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411/*
3412 * Analog playback callbacks
3413 */
3414static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
3415 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003416 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417{
3418 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01003419 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
3420 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421}
3422
3423static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
3424 struct hda_codec *codec,
3425 unsigned int stream_tag,
3426 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003427 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428{
3429 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003430 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
3431 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432}
3433
3434static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3435 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003436 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437{
3438 struct alc_spec *spec = codec->spec;
3439 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
3440}
3441
3442/*
3443 * Digital out
3444 */
3445static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
3446 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003447 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448{
3449 struct alc_spec *spec = codec->spec;
3450 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
3451}
3452
Takashi Iwai6b97eb42007-04-05 14:51:48 +02003453static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
3454 struct hda_codec *codec,
3455 unsigned int stream_tag,
3456 unsigned int format,
3457 struct snd_pcm_substream *substream)
3458{
3459 struct alc_spec *spec = codec->spec;
3460 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
3461 stream_tag, format, substream);
3462}
3463
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01003464static int alc880_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3465 struct hda_codec *codec,
3466 struct snd_pcm_substream *substream)
3467{
3468 struct alc_spec *spec = codec->spec;
3469 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
3470}
3471
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
3473 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003474 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475{
3476 struct alc_spec *spec = codec->spec;
3477 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
3478}
3479
3480/*
3481 * Analog capture
3482 */
Takashi Iwai63300792008-01-24 15:31:36 +01003483static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484 struct hda_codec *codec,
3485 unsigned int stream_tag,
3486 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003487 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488{
3489 struct alc_spec *spec = codec->spec;
3490
Takashi Iwai63300792008-01-24 15:31:36 +01003491 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492 stream_tag, 0, format);
3493 return 0;
3494}
3495
Takashi Iwai63300792008-01-24 15:31:36 +01003496static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003498 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499{
3500 struct alc_spec *spec = codec->spec;
3501
Takashi Iwai888afa12008-03-18 09:57:50 +01003502 snd_hda_codec_cleanup_stream(codec,
3503 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504 return 0;
3505}
3506
3507
3508/*
3509 */
3510static struct hda_pcm_stream alc880_pcm_analog_playback = {
3511 .substreams = 1,
3512 .channels_min = 2,
3513 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003514 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515 .ops = {
3516 .open = alc880_playback_pcm_open,
3517 .prepare = alc880_playback_pcm_prepare,
3518 .cleanup = alc880_playback_pcm_cleanup
3519 },
3520};
3521
3522static struct hda_pcm_stream alc880_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01003523 .substreams = 1,
3524 .channels_min = 2,
3525 .channels_max = 2,
3526 /* NID is set in alc_build_pcms */
3527};
3528
3529static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
3530 .substreams = 1,
3531 .channels_min = 2,
3532 .channels_max = 2,
3533 /* NID is set in alc_build_pcms */
3534};
3535
3536static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
3537 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538 .channels_min = 2,
3539 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003540 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541 .ops = {
Takashi Iwai63300792008-01-24 15:31:36 +01003542 .prepare = alc880_alt_capture_pcm_prepare,
3543 .cleanup = alc880_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 },
3545};
3546
3547static struct hda_pcm_stream alc880_pcm_digital_playback = {
3548 .substreams = 1,
3549 .channels_min = 2,
3550 .channels_max = 2,
3551 /* NID is set in alc_build_pcms */
3552 .ops = {
3553 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02003554 .close = alc880_dig_playback_pcm_close,
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01003555 .prepare = alc880_dig_playback_pcm_prepare,
3556 .cleanup = alc880_dig_playback_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557 },
3558};
3559
3560static struct hda_pcm_stream alc880_pcm_digital_capture = {
3561 .substreams = 1,
3562 .channels_min = 2,
3563 .channels_max = 2,
3564 /* NID is set in alc_build_pcms */
3565};
3566
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003567/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwai63300792008-01-24 15:31:36 +01003568static struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003569 .substreams = 0,
3570 .channels_min = 0,
3571 .channels_max = 0,
3572};
3573
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574static int alc_build_pcms(struct hda_codec *codec)
3575{
3576 struct alc_spec *spec = codec->spec;
3577 struct hda_pcm *info = spec->pcm_rec;
3578 int i;
3579
3580 codec->num_pcms = 1;
3581 codec->pcm_info = info;
3582
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003583 if (spec->no_analog)
3584 goto skip_analog;
3585
Takashi Iwai812a2cc2009-05-16 10:00:49 +02003586 snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog),
3587 "%s Analog", codec->chip_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 info->name = spec->stream_name_analog;
Kailang Yang274693f2009-12-03 10:07:50 +01003589
Takashi Iwai4a471b72005-12-07 13:56:29 +01003590 if (spec->stream_analog_playback) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02003591 if (snd_BUG_ON(!spec->multiout.dac_nids))
3592 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003593 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
3594 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
3595 }
3596 if (spec->stream_analog_capture) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02003597 if (snd_BUG_ON(!spec->adc_nids))
3598 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003599 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
3600 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
3601 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602
Takashi Iwai4a471b72005-12-07 13:56:29 +01003603 if (spec->channel_mode) {
3604 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
3605 for (i = 0; i < spec->num_channel_mode; i++) {
3606 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
3607 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
3608 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 }
3610 }
3611
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003612 skip_analog:
Takashi Iwaie08a0072006-09-07 17:52:14 +02003613 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwai812a2cc2009-05-16 10:00:49 +02003615 snprintf(spec->stream_name_digital,
3616 sizeof(spec->stream_name_digital),
3617 "%s Digital", codec->chip_name);
Takashi Iwaie08a0072006-09-07 17:52:14 +02003618 codec->num_pcms = 2;
Wu Fengguangb25c9da2009-02-06 15:02:27 +08003619 codec->slave_dig_outs = spec->multiout.slave_dig_outs;
Takashi Iwaic06134d2006-10-11 18:49:13 +02003620 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621 info->name = spec->stream_name_digital;
Takashi Iwai8c441982009-01-20 18:30:20 +01003622 if (spec->dig_out_type)
3623 info->pcm_type = spec->dig_out_type;
3624 else
3625 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003626 if (spec->multiout.dig_out_nid &&
3627 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
3629 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
3630 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01003631 if (spec->dig_in_nid &&
3632 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
3634 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
3635 }
Takashi Iwai963f8032008-08-11 10:04:40 +02003636 /* FIXME: do we need this for all Realtek codec models? */
3637 codec->spdif_status_reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638 }
3639
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003640 if (spec->no_analog)
3641 return 0;
3642
Takashi Iwaie08a0072006-09-07 17:52:14 +02003643 /* If the use of more than one ADC is requested for the current
3644 * model, configure a second analog capture-only PCM.
3645 */
3646 /* Additional Analaog capture for index #2 */
Takashi Iwai63300792008-01-24 15:31:36 +01003647 if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
3648 (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02003649 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02003650 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02003651 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01003652 if (spec->alt_dac_nid) {
3653 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
3654 *spec->stream_analog_alt_playback;
3655 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
3656 spec->alt_dac_nid;
3657 } else {
3658 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
3659 alc_pcm_null_stream;
3660 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
3661 }
3662 if (spec->num_adc_nids > 1) {
3663 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
3664 *spec->stream_analog_alt_capture;
3665 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
3666 spec->adc_nids[1];
3667 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
3668 spec->num_adc_nids - 1;
3669 } else {
3670 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
3671 alc_pcm_null_stream;
3672 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02003673 }
3674 }
3675
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676 return 0;
3677}
3678
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01003679static inline void alc_shutup(struct hda_codec *codec)
3680{
3681 snd_hda_shutup_pins(codec);
3682}
3683
Takashi Iwai603c4012008-07-30 15:01:44 +02003684static void alc_free_kctls(struct hda_codec *codec)
3685{
3686 struct alc_spec *spec = codec->spec;
3687
3688 if (spec->kctls.list) {
3689 struct snd_kcontrol_new *kctl = spec->kctls.list;
3690 int i;
3691 for (i = 0; i < spec->kctls.used; i++)
3692 kfree(kctl[i].name);
3693 }
3694 snd_array_free(&spec->kctls);
3695}
3696
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697static void alc_free(struct hda_codec *codec)
3698{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003699 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003700
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003701 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003702 return;
3703
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01003704 alc_shutup(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +02003705 alc_free_kctls(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003706 kfree(spec);
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09003707 snd_hda_detach_beep_device(codec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708}
3709
Hector Martinf5de24b2009-12-20 22:51:31 +01003710#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -05003711static void alc_power_eapd(struct hda_codec *codec)
3712{
3713 /* We currently only handle front, HP */
3714 switch (codec->vendor_id) {
3715 case 0x10ec0260:
Takashi Iwai9e4c8492010-01-19 15:53:43 +01003716 set_eapd(codec, 0x0f, 0);
3717 set_eapd(codec, 0x10, 0);
Daniel T Chenc97259d2009-12-27 18:52:08 -05003718 break;
3719 case 0x10ec0262:
3720 case 0x10ec0267:
3721 case 0x10ec0268:
3722 case 0x10ec0269:
Takashi Iwai9e4c8492010-01-19 15:53:43 +01003723 case 0x10ec0270:
Daniel T Chenc97259d2009-12-27 18:52:08 -05003724 case 0x10ec0272:
3725 case 0x10ec0660:
3726 case 0x10ec0662:
3727 case 0x10ec0663:
3728 case 0x10ec0862:
3729 case 0x10ec0889:
Takashi Iwai9e4c8492010-01-19 15:53:43 +01003730 set_eapd(codec, 0x14, 0);
3731 set_eapd(codec, 0x15, 0);
Daniel T Chenc97259d2009-12-27 18:52:08 -05003732 break;
3733 }
3734}
3735
Hector Martinf5de24b2009-12-20 22:51:31 +01003736static int alc_suspend(struct hda_codec *codec, pm_message_t state)
3737{
3738 struct alc_spec *spec = codec->spec;
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01003739 alc_shutup(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01003740 if (spec && spec->power_hook)
Daniel T Chenc97259d2009-12-27 18:52:08 -05003741 spec->power_hook(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01003742 return 0;
3743}
3744#endif
3745
Takashi Iwaie044c392008-10-27 16:56:24 +01003746#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaie044c392008-10-27 16:56:24 +01003747static int alc_resume(struct hda_codec *codec)
3748{
Takashi Iwaie044c392008-10-27 16:56:24 +01003749 codec->patch_ops.init(codec);
3750 snd_hda_codec_resume_amp(codec);
3751 snd_hda_codec_resume_cache(codec);
3752 return 0;
3753}
Takashi Iwaie044c392008-10-27 16:56:24 +01003754#endif
3755
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756/*
3757 */
3758static struct hda_codec_ops alc_patch_ops = {
3759 .build_controls = alc_build_controls,
3760 .build_pcms = alc_build_pcms,
3761 .init = alc_init,
3762 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003763 .unsol_event = alc_unsol_event,
Takashi Iwaie044c392008-10-27 16:56:24 +01003764#ifdef SND_HDA_NEEDS_RESUME
3765 .resume = alc_resume,
3766#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02003767#ifdef CONFIG_SND_HDA_POWER_SAVE
Hector Martinf5de24b2009-12-20 22:51:31 +01003768 .suspend = alc_suspend,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003769 .check_power_status = alc_check_power_status,
3770#endif
Daniel T Chenc97259d2009-12-27 18:52:08 -05003771 .reboot_notify = alc_shutup,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772};
3773
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003774
3775/*
3776 * Test configuration for debugging
3777 *
3778 * Almost all inputs/outputs are enabled. I/O pins can be configured via
3779 * enum controls.
3780 */
3781#ifdef CONFIG_SND_DEBUG
3782static hda_nid_t alc880_test_dac_nids[4] = {
3783 0x02, 0x03, 0x04, 0x05
3784};
3785
3786static struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003787 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003788 .items = {
3789 { "In-1", 0x0 },
3790 { "In-2", 0x1 },
3791 { "In-3", 0x2 },
3792 { "In-4", 0x3 },
3793 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003794 { "Front", 0x5 },
3795 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003796 },
3797};
3798
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01003799static struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003800 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02003801 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003802 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02003803 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003804};
3805
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003806static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
3807 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003808{
3809 static char *texts[] = {
3810 "N/A", "Line Out", "HP Out",
3811 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
3812 };
3813 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3814 uinfo->count = 1;
3815 uinfo->value.enumerated.items = 8;
3816 if (uinfo->value.enumerated.item >= 8)
3817 uinfo->value.enumerated.item = 7;
3818 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
3819 return 0;
3820}
3821
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003822static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
3823 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003824{
3825 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3826 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3827 unsigned int pin_ctl, item = 0;
3828
3829 pin_ctl = snd_hda_codec_read(codec, nid, 0,
3830 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3831 if (pin_ctl & AC_PINCTL_OUT_EN) {
3832 if (pin_ctl & AC_PINCTL_HP_EN)
3833 item = 2;
3834 else
3835 item = 1;
3836 } else if (pin_ctl & AC_PINCTL_IN_EN) {
3837 switch (pin_ctl & AC_PINCTL_VREFEN) {
3838 case AC_PINCTL_VREF_HIZ: item = 3; break;
3839 case AC_PINCTL_VREF_50: item = 4; break;
3840 case AC_PINCTL_VREF_GRD: item = 5; break;
3841 case AC_PINCTL_VREF_80: item = 6; break;
3842 case AC_PINCTL_VREF_100: item = 7; break;
3843 }
3844 }
3845 ucontrol->value.enumerated.item[0] = item;
3846 return 0;
3847}
3848
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003849static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
3850 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003851{
3852 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3853 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3854 static unsigned int ctls[] = {
3855 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
3856 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
3857 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
3858 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
3859 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
3860 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
3861 };
3862 unsigned int old_ctl, new_ctl;
3863
3864 old_ctl = snd_hda_codec_read(codec, nid, 0,
3865 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3866 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
3867 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003868 int val;
3869 snd_hda_codec_write_cache(codec, nid, 0,
3870 AC_VERB_SET_PIN_WIDGET_CONTROL,
3871 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02003872 val = ucontrol->value.enumerated.item[0] >= 3 ?
3873 HDA_AMP_MUTE : 0;
3874 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
3875 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003876 return 1;
3877 }
3878 return 0;
3879}
3880
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003881static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
3882 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003883{
3884 static char *texts[] = {
3885 "Front", "Surround", "CLFE", "Side"
3886 };
3887 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3888 uinfo->count = 1;
3889 uinfo->value.enumerated.items = 4;
3890 if (uinfo->value.enumerated.item >= 4)
3891 uinfo->value.enumerated.item = 3;
3892 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
3893 return 0;
3894}
3895
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003896static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
3897 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003898{
3899 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3900 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3901 unsigned int sel;
3902
3903 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
3904 ucontrol->value.enumerated.item[0] = sel & 3;
3905 return 0;
3906}
3907
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003908static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
3909 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003910{
3911 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3912 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3913 unsigned int sel;
3914
3915 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
3916 if (ucontrol->value.enumerated.item[0] != sel) {
3917 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003918 snd_hda_codec_write_cache(codec, nid, 0,
3919 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003920 return 1;
3921 }
3922 return 0;
3923}
3924
3925#define PIN_CTL_TEST(xname,nid) { \
3926 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3927 .name = xname, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003928 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003929 .info = alc_test_pin_ctl_info, \
3930 .get = alc_test_pin_ctl_get, \
3931 .put = alc_test_pin_ctl_put, \
3932 .private_value = nid \
3933 }
3934
3935#define PIN_SRC_TEST(xname,nid) { \
3936 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3937 .name = xname, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003938 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003939 .info = alc_test_pin_src_info, \
3940 .get = alc_test_pin_src_get, \
3941 .put = alc_test_pin_src_put, \
3942 .private_value = nid \
3943 }
3944
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003945static struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003946 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3947 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3948 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
3949 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003950 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
3951 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
3952 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
3953 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003954 PIN_CTL_TEST("Front Pin Mode", 0x14),
3955 PIN_CTL_TEST("Surround Pin Mode", 0x15),
3956 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
3957 PIN_CTL_TEST("Side Pin Mode", 0x17),
3958 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
3959 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
3960 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
3961 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
3962 PIN_SRC_TEST("In-1 Pin Source", 0x18),
3963 PIN_SRC_TEST("In-2 Pin Source", 0x19),
3964 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
3965 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
3966 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
3967 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
3968 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
3969 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
3970 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
3971 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
3972 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
3973 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
3974 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
3975 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003976 {
3977 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3978 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01003979 .info = alc_ch_mode_info,
3980 .get = alc_ch_mode_get,
3981 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003982 },
3983 { } /* end */
3984};
3985
3986static struct hda_verb alc880_test_init_verbs[] = {
3987 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02003988 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3989 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3990 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3991 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3992 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3993 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3994 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3995 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003996 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02003997 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3998 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3999 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4000 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004001 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004002 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4003 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4004 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4005 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004006 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004007 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4008 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4009 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4010 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004011 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02004012 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4013 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02004014 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4015 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4016 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004017 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02004018 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4019 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4020 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4021 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004022 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02004023 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004024 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004025 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004026 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004027 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004028 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004029 /* Analog input/passthru */
4030 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4031 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4032 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4033 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4034 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004035 { }
4036};
4037#endif
4038
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039/*
4040 */
4041
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004042static const char *alc880_models[ALC880_MODEL_LAST] = {
4043 [ALC880_3ST] = "3stack",
4044 [ALC880_TCL_S700] = "tcl",
4045 [ALC880_3ST_DIG] = "3stack-digout",
4046 [ALC880_CLEVO] = "clevo",
4047 [ALC880_5ST] = "5stack",
4048 [ALC880_5ST_DIG] = "5stack-digout",
4049 [ALC880_W810] = "w810",
4050 [ALC880_Z71V] = "z71v",
4051 [ALC880_6ST] = "6stack",
4052 [ALC880_6ST_DIG] = "6stack-digout",
4053 [ALC880_ASUS] = "asus",
4054 [ALC880_ASUS_W1V] = "asus-w1v",
4055 [ALC880_ASUS_DIG] = "asus-dig",
4056 [ALC880_ASUS_DIG2] = "asus-dig2",
4057 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004058 [ALC880_UNIWILL_P53] = "uniwill-p53",
4059 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004060 [ALC880_F1734] = "F1734",
4061 [ALC880_LG] = "lg",
4062 [ALC880_LG_LW] = "lg-lw",
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004063 [ALC880_MEDION_RIM] = "medion",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004064#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004065 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004066#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004067 [ALC880_AUTO] = "auto",
4068};
4069
4070static struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004071 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004072 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
4073 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
4074 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
4075 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
4076 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
4077 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
4078 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
4079 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004080 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
4081 SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004082 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
4083 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
4084 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
4085 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
4086 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
4087 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
4088 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
4089 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
4090 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
4091 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Travis Place186c3112008-05-20 11:54:41 +02004092 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004093 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
4094 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
4095 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004096 SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004097 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004098 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
4099 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004100 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
4101 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004102 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
4103 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
4104 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
4105 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004106 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
4107 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004108 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004109 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004110 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004111 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004112 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
4113 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004114 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004115 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004116 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004117 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004118 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Travis Place1d116042008-06-23 11:42:30 +02004119 SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004120 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004121 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004122 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004123 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
4124 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004125 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004126 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
4127 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
4128 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
4129 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004130 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
4131 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004132 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004133 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004134 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
4135 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004136 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
4137 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
4138 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004139 /* default Intel */
4140 SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004141 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
4142 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004143 {}
4144};
4145
Takashi Iwai16ded522005-06-10 19:58:24 +02004146/*
Kailang Yangdf694da2005-12-05 19:42:22 +01004147 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02004148 */
Takashi Iwai16ded522005-06-10 19:58:24 +02004149static struct alc_config_preset alc880_presets[] = {
4150 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004151 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004152 .init_verbs = { alc880_volume_init_verbs,
4153 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004154 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02004155 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004156 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4157 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004158 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004159 .input_mux = &alc880_capture_source,
4160 },
4161 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004162 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004163 .init_verbs = { alc880_volume_init_verbs,
4164 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004165 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02004166 .dac_nids = alc880_dac_nids,
4167 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004168 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4169 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004170 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004171 .input_mux = &alc880_capture_source,
4172 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004173 [ALC880_TCL_S700] = {
4174 .mixers = { alc880_tcl_s700_mixer },
4175 .init_verbs = { alc880_volume_init_verbs,
4176 alc880_pin_tcl_S700_init_verbs,
4177 alc880_gpio2_init_verbs },
4178 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4179 .dac_nids = alc880_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004180 .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */
4181 .num_adc_nids = 1, /* single ADC */
Kailang Yangdf694da2005-12-05 19:42:22 +01004182 .hp_nid = 0x03,
4183 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4184 .channel_mode = alc880_2_jack_modes,
4185 .input_mux = &alc880_capture_source,
4186 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004187 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004188 .mixers = { alc880_three_stack_mixer,
4189 alc880_five_stack_mixer},
4190 .init_verbs = { alc880_volume_init_verbs,
4191 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004192 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4193 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004194 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
4195 .channel_mode = alc880_fivestack_modes,
4196 .input_mux = &alc880_capture_source,
4197 },
4198 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004199 .mixers = { alc880_three_stack_mixer,
4200 alc880_five_stack_mixer },
4201 .init_verbs = { alc880_volume_init_verbs,
4202 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004203 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4204 .dac_nids = alc880_dac_nids,
4205 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004206 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
4207 .channel_mode = alc880_fivestack_modes,
4208 .input_mux = &alc880_capture_source,
4209 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02004210 [ALC880_6ST] = {
4211 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004212 .init_verbs = { alc880_volume_init_verbs,
4213 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02004214 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
4215 .dac_nids = alc880_6st_dac_nids,
4216 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
4217 .channel_mode = alc880_sixstack_modes,
4218 .input_mux = &alc880_6stack_capture_source,
4219 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004220 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004221 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004222 .init_verbs = { alc880_volume_init_verbs,
4223 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004224 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
4225 .dac_nids = alc880_6st_dac_nids,
4226 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004227 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
4228 .channel_mode = alc880_sixstack_modes,
4229 .input_mux = &alc880_6stack_capture_source,
4230 },
4231 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004232 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004233 .init_verbs = { alc880_volume_init_verbs,
4234 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02004235 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004236 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
4237 .dac_nids = alc880_w810_dac_nids,
4238 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004239 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
4240 .channel_mode = alc880_w810_modes,
4241 .input_mux = &alc880_capture_source,
4242 },
4243 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004244 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004245 .init_verbs = { alc880_volume_init_verbs,
4246 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004247 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
4248 .dac_nids = alc880_z71v_dac_nids,
4249 .dig_out_nid = ALC880_DIGOUT_NID,
4250 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004251 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4252 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02004253 .input_mux = &alc880_capture_source,
4254 },
4255 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004256 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004257 .init_verbs = { alc880_volume_init_verbs,
4258 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004259 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
4260 .dac_nids = alc880_f1734_dac_nids,
4261 .hp_nid = 0x02,
4262 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4263 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01004264 .input_mux = &alc880_f1734_capture_source,
4265 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004266 .setup = alc880_uniwill_p53_setup,
4267 .init_hook = alc_automute_amp,
Takashi Iwai16ded522005-06-10 19:58:24 +02004268 },
4269 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004270 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004271 .init_verbs = { alc880_volume_init_verbs,
4272 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004273 alc880_gpio1_init_verbs },
4274 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4275 .dac_nids = alc880_asus_dac_nids,
4276 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4277 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004278 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004279 .input_mux = &alc880_capture_source,
4280 },
4281 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004282 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004283 .init_verbs = { alc880_volume_init_verbs,
4284 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004285 alc880_gpio1_init_verbs },
4286 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4287 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004288 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004289 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4290 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004291 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004292 .input_mux = &alc880_capture_source,
4293 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004294 [ALC880_ASUS_DIG2] = {
4295 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004296 .init_verbs = { alc880_volume_init_verbs,
4297 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01004298 alc880_gpio2_init_verbs }, /* use GPIO2 */
4299 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4300 .dac_nids = alc880_asus_dac_nids,
4301 .dig_out_nid = ALC880_DIGOUT_NID,
4302 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4303 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004304 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01004305 .input_mux = &alc880_capture_source,
4306 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004307 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004308 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004309 .init_verbs = { alc880_volume_init_verbs,
4310 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004311 alc880_gpio1_init_verbs },
4312 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4313 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004314 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004315 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4316 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004317 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004318 .input_mux = &alc880_capture_source,
4319 },
4320 [ALC880_UNIWILL_DIG] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004321 .mixers = { alc880_asus_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02004322 .init_verbs = { alc880_volume_init_verbs,
4323 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004324 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4325 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004326 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004327 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4328 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004329 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004330 .input_mux = &alc880_capture_source,
4331 },
Kailang Yangccc656c2006-10-17 12:32:26 +02004332 [ALC880_UNIWILL] = {
4333 .mixers = { alc880_uniwill_mixer },
4334 .init_verbs = { alc880_volume_init_verbs,
4335 alc880_uniwill_init_verbs },
4336 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4337 .dac_nids = alc880_asus_dac_nids,
4338 .dig_out_nid = ALC880_DIGOUT_NID,
4339 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4340 .channel_mode = alc880_threestack_modes,
4341 .need_dac_fix = 1,
4342 .input_mux = &alc880_capture_source,
4343 .unsol_event = alc880_uniwill_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004344 .setup = alc880_uniwill_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004345 .init_hook = alc880_uniwill_init_hook,
Kailang Yangccc656c2006-10-17 12:32:26 +02004346 },
4347 [ALC880_UNIWILL_P53] = {
4348 .mixers = { alc880_uniwill_p53_mixer },
4349 .init_verbs = { alc880_volume_init_verbs,
4350 alc880_uniwill_p53_init_verbs },
4351 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4352 .dac_nids = alc880_asus_dac_nids,
4353 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004354 .channel_mode = alc880_threestack_modes,
4355 .input_mux = &alc880_capture_source,
4356 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004357 .setup = alc880_uniwill_p53_setup,
4358 .init_hook = alc_automute_amp,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004359 },
4360 [ALC880_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004361 .mixers = { alc880_fujitsu_mixer },
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004362 .init_verbs = { alc880_volume_init_verbs,
4363 alc880_uniwill_p53_init_verbs,
4364 alc880_beep_init_verbs },
4365 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4366 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02004367 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004368 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4369 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02004370 .input_mux = &alc880_capture_source,
4371 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004372 .setup = alc880_uniwill_p53_setup,
4373 .init_hook = alc_automute_amp,
Kailang Yangccc656c2006-10-17 12:32:26 +02004374 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004375 [ALC880_CLEVO] = {
4376 .mixers = { alc880_three_stack_mixer },
4377 .init_verbs = { alc880_volume_init_verbs,
4378 alc880_pin_clevo_init_verbs },
4379 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4380 .dac_nids = alc880_dac_nids,
4381 .hp_nid = 0x03,
4382 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4383 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004384 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01004385 .input_mux = &alc880_capture_source,
4386 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004387 [ALC880_LG] = {
4388 .mixers = { alc880_lg_mixer },
4389 .init_verbs = { alc880_volume_init_verbs,
4390 alc880_lg_init_verbs },
4391 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
4392 .dac_nids = alc880_lg_dac_nids,
4393 .dig_out_nid = ALC880_DIGOUT_NID,
4394 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
4395 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004396 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004397 .input_mux = &alc880_lg_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004398 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004399 .setup = alc880_lg_setup,
4400 .init_hook = alc_automute_amp,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004401#ifdef CONFIG_SND_HDA_POWER_SAVE
4402 .loopbacks = alc880_lg_loopbacks,
4403#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004404 },
Takashi Iwaid6815182006-03-23 16:06:23 +01004405 [ALC880_LG_LW] = {
4406 .mixers = { alc880_lg_lw_mixer },
4407 .init_verbs = { alc880_volume_init_verbs,
4408 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004409 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01004410 .dac_nids = alc880_dac_nids,
4411 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004412 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
4413 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01004414 .input_mux = &alc880_lg_lw_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004415 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004416 .setup = alc880_lg_lw_setup,
4417 .init_hook = alc_automute_amp,
Takashi Iwaid6815182006-03-23 16:06:23 +01004418 },
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004419 [ALC880_MEDION_RIM] = {
4420 .mixers = { alc880_medion_rim_mixer },
4421 .init_verbs = { alc880_volume_init_verbs,
4422 alc880_medion_rim_init_verbs,
4423 alc_gpio2_init_verbs },
4424 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4425 .dac_nids = alc880_dac_nids,
4426 .dig_out_nid = ALC880_DIGOUT_NID,
4427 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4428 .channel_mode = alc880_2_jack_modes,
4429 .input_mux = &alc880_medion_rim_capture_source,
4430 .unsol_event = alc880_medion_rim_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004431 .setup = alc880_medion_rim_setup,
4432 .init_hook = alc880_medion_rim_automute,
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004433 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004434#ifdef CONFIG_SND_DEBUG
4435 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004436 .mixers = { alc880_test_mixer },
4437 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004438 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
4439 .dac_nids = alc880_test_dac_nids,
4440 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004441 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
4442 .channel_mode = alc880_test_modes,
4443 .input_mux = &alc880_test_capture_source,
4444 },
4445#endif
4446};
4447
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004448/*
4449 * Automatic parse of I/O pins from the BIOS configuration
4450 */
4451
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004452enum {
4453 ALC_CTL_WIDGET_VOL,
4454 ALC_CTL_WIDGET_MUTE,
4455 ALC_CTL_BIND_MUTE,
4456};
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004457static struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004458 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
4459 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01004460 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004461};
4462
4463/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004464static int add_control(struct alc_spec *spec, int type, const char *name,
4465 unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004466{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004467 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004468
Takashi Iwai603c4012008-07-30 15:01:44 +02004469 snd_array_init(&spec->kctls, sizeof(*knew), 32);
4470 knew = snd_array_new(&spec->kctls);
4471 if (!knew)
4472 return -ENOMEM;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004473 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07004474 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004475 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004476 return -ENOMEM;
Jaroslav Kysela4d02d1b2009-11-12 10:15:48 +01004477 if (get_amp_nid_(val))
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01004478 knew->subdevice = HDA_SUBDEV_AMP_FLAG;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004479 knew->private_value = val;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004480 return 0;
4481}
4482
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004483static int add_control_with_pfx(struct alc_spec *spec, int type,
4484 const char *pfx, const char *dir,
4485 const char *sfx, unsigned long val)
4486{
4487 char name[32];
4488 snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
4489 return add_control(spec, type, name, val);
4490}
4491
4492#define add_pb_vol_ctrl(spec, type, pfx, val) \
4493 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", val)
4494#define add_pb_sw_ctrl(spec, type, pfx, val) \
4495 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", val)
4496
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004497#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
4498#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
4499#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
4500#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004501#define alc880_idx_to_dac(nid) ((nid) + 0x02)
4502#define alc880_dac_to_idx(nid) ((nid) - 0x02)
4503#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
4504#define alc880_idx_to_selector(nid) ((nid) + 0x10)
4505#define ALC880_PIN_CD_NID 0x1c
4506
4507/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004508static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
4509 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004510{
4511 hda_nid_t nid;
4512 int assigned[4];
4513 int i, j;
4514
4515 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02004516 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004517
4518 /* check the pins hardwired to audio widget */
4519 for (i = 0; i < cfg->line_outs; i++) {
4520 nid = cfg->line_out_pins[i];
4521 if (alc880_is_fixed_pin(nid)) {
4522 int idx = alc880_fixed_pin_idx(nid);
Libin Yang5014f192005-11-23 15:48:36 +01004523 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004524 assigned[idx] = 1;
4525 }
4526 }
4527 /* left pins can be connect to any audio widget */
4528 for (i = 0; i < cfg->line_outs; i++) {
4529 nid = cfg->line_out_pins[i];
4530 if (alc880_is_fixed_pin(nid))
4531 continue;
4532 /* search for an empty channel */
4533 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004534 if (!assigned[j]) {
4535 spec->multiout.dac_nids[i] =
4536 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004537 assigned[j] = 1;
4538 break;
4539 }
4540 }
4541 }
4542 spec->multiout.num_dacs = cfg->line_outs;
4543 return 0;
4544}
4545
4546/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01004547static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
4548 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004549{
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004550 static const char *chname[4] = {
4551 "Front", "Surround", NULL /*CLFE*/, "Side"
4552 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004553 hda_nid_t nid;
4554 int i, err;
4555
4556 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004557 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004558 continue;
4559 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
4560 if (i == 2) {
4561 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004562 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
4563 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004564 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
4565 HDA_OUTPUT));
4566 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004567 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004568 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
4569 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004570 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
4571 HDA_OUTPUT));
4572 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004573 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004574 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
4575 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004576 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
4577 HDA_INPUT));
4578 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004579 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004580 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
4581 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004582 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
4583 HDA_INPUT));
4584 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004585 return err;
4586 } else {
Takashi Iwaicb162b62009-08-25 16:05:03 +02004587 const char *pfx;
4588 if (cfg->line_outs == 1 &&
4589 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
4590 pfx = "Speaker";
4591 else
4592 pfx = chname[i];
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004593 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004594 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
4595 HDA_OUTPUT));
4596 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004597 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004598 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004599 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
4600 HDA_INPUT));
4601 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004602 return err;
4603 }
4604 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004605 return 0;
4606}
4607
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004608/* add playback controls for speaker and HP outputs */
4609static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
4610 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004611{
4612 hda_nid_t nid;
4613 int err;
4614
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004615 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004616 return 0;
4617
4618 if (alc880_is_fixed_pin(pin)) {
4619 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01004620 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004621 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004622 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01004623 else
4624 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004625 /* control HP volume/switch on the output mixer amp */
4626 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004627 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004628 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
4629 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004630 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004631 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004632 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
4633 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004634 return err;
4635 } else if (alc880_is_multi_pin(pin)) {
4636 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004637 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004638 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004639 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
4640 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004641 return err;
4642 }
4643 return 0;
4644}
4645
4646/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004647static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
4648 const char *ctlname,
Kailang Yangdf694da2005-12-05 19:42:22 +01004649 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004650{
Kailang Yangdf694da2005-12-05 19:42:22 +01004651 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004652
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004653 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004654 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
4655 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004656 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004657 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004658 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
4659 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004660 return err;
4661 return 0;
4662}
4663
Takashi Iwai05f5f472009-08-25 13:10:18 +02004664static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004665{
Takashi Iwai05f5f472009-08-25 13:10:18 +02004666 unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
4667 return (pincap & AC_PINCAP_IN) != 0;
4668}
4669
4670/* create playback/capture controls for input pins */
4671static int alc_auto_create_input_ctls(struct hda_codec *codec,
4672 const struct auto_pin_cfg *cfg,
4673 hda_nid_t mixer,
4674 hda_nid_t cap1, hda_nid_t cap2)
4675{
4676 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02004677 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004678 int i, err, idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004679
4680 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai05f5f472009-08-25 13:10:18 +02004681 hda_nid_t pin;
4682
4683 pin = cfg->input_pins[i];
4684 if (!alc_is_input_pin(codec, pin))
4685 continue;
4686
4687 if (mixer) {
4688 idx = get_connection_index(codec, mixer, pin);
4689 if (idx >= 0) {
4690 err = new_analog_input(spec, pin,
4691 auto_pin_cfg_labels[i],
4692 idx, mixer);
4693 if (err < 0)
4694 return err;
4695 }
4696 }
4697
4698 if (!cap1)
4699 continue;
4700 idx = get_connection_index(codec, cap1, pin);
4701 if (idx < 0 && cap2)
4702 idx = get_connection_index(codec, cap2, pin);
4703 if (idx >= 0) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004704 imux->items[imux->num_items].label =
4705 auto_pin_cfg_labels[i];
Takashi Iwai05f5f472009-08-25 13:10:18 +02004706 imux->items[imux->num_items].index = idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004707 imux->num_items++;
4708 }
4709 }
4710 return 0;
4711}
4712
Takashi Iwai05f5f472009-08-25 13:10:18 +02004713static int alc880_auto_create_input_ctls(struct hda_codec *codec,
4714 const struct auto_pin_cfg *cfg)
4715{
4716 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x08, 0x09);
4717}
4718
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004719static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
4720 unsigned int pin_type)
4721{
4722 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4723 pin_type);
4724 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01004725 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
4726 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004727}
4728
Kailang Yangdf694da2005-12-05 19:42:22 +01004729static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
4730 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004731 int dac_idx)
4732{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004733 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004734 /* need the manual connection? */
4735 if (alc880_is_multi_pin(nid)) {
4736 struct alc_spec *spec = codec->spec;
4737 int idx = alc880_multi_pin_idx(nid);
4738 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
4739 AC_VERB_SET_CONNECT_SEL,
4740 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
4741 }
4742}
4743
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004744static int get_pin_type(int line_out_type)
4745{
4746 if (line_out_type == AUTO_PIN_HP_OUT)
4747 return PIN_HP;
4748 else
4749 return PIN_OUT;
4750}
4751
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004752static void alc880_auto_init_multi_out(struct hda_codec *codec)
4753{
4754 struct alc_spec *spec = codec->spec;
4755 int i;
Kailang Yangea1fb292008-08-26 12:58:38 +02004756
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004757 for (i = 0; i < spec->autocfg.line_outs; i++) {
4758 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004759 int pin_type = get_pin_type(spec->autocfg.line_out_type);
4760 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004761 }
4762}
4763
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004764static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004765{
4766 struct alc_spec *spec = codec->spec;
4767 hda_nid_t pin;
4768
Takashi Iwai82bc9552006-03-21 11:24:42 +01004769 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004770 if (pin) /* connect to front */
4771 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004772 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004773 if (pin) /* connect to front */
4774 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
4775}
4776
4777static void alc880_auto_init_analog_input(struct hda_codec *codec)
4778{
4779 struct alc_spec *spec = codec->spec;
4780 int i;
4781
4782 for (i = 0; i < AUTO_PIN_LAST; i++) {
4783 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai05f5f472009-08-25 13:10:18 +02004784 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +01004785 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +01004786 if (nid != ALC880_PIN_CD_NID &&
4787 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004788 snd_hda_codec_write(codec, nid, 0,
4789 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004790 AMP_OUT_MUTE);
4791 }
4792 }
4793}
4794
4795/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004796/* return 1 if successful, 0 if the proper config is not found,
4797 * or a negative error code
4798 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004799static int alc880_parse_auto_config(struct hda_codec *codec)
4800{
4801 struct alc_spec *spec = codec->spec;
Takashi Iwai6a05ac42009-02-13 11:19:09 +01004802 int i, err;
Kailang Yangdf694da2005-12-05 19:42:22 +01004803 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004804
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004805 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
4806 alc880_ignore);
4807 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004808 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004809 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004810 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01004811
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004812 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
4813 if (err < 0)
4814 return err;
4815 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
4816 if (err < 0)
4817 return err;
4818 err = alc880_auto_create_extra_out(spec,
4819 spec->autocfg.speaker_pins[0],
4820 "Speaker");
4821 if (err < 0)
4822 return err;
4823 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
4824 "Headphone");
4825 if (err < 0)
4826 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +02004827 err = alc880_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004828 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004829 return err;
4830
4831 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
4832
Takashi Iwai6a05ac42009-02-13 11:19:09 +01004833 /* check multiple SPDIF-out (for recent codecs) */
4834 for (i = 0; i < spec->autocfg.dig_outs; i++) {
4835 hda_nid_t dig_nid;
4836 err = snd_hda_get_connections(codec,
4837 spec->autocfg.dig_out_pins[i],
4838 &dig_nid, 1);
4839 if (err < 0)
4840 continue;
4841 if (!i)
4842 spec->multiout.dig_out_nid = dig_nid;
4843 else {
4844 spec->multiout.slave_dig_outs = spec->slave_dig_outs;
Roel Kluin71121d9f2009-11-10 20:11:55 +01004845 if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
Takashi Iwai6a05ac42009-02-13 11:19:09 +01004846 break;
Roel Kluin71121d9f2009-11-10 20:11:55 +01004847 spec->slave_dig_outs[i - 1] = dig_nid;
Takashi Iwai6a05ac42009-02-13 11:19:09 +01004848 }
4849 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004850 if (spec->autocfg.dig_in_pin)
4851 spec->dig_in_nid = ALC880_DIGIN_NID;
4852
Takashi Iwai603c4012008-07-30 15:01:44 +02004853 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01004854 add_mixer(spec, spec->kctls.list);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004855
Takashi Iwaid88897e2008-10-31 15:01:37 +01004856 add_verb(spec, alc880_volume_init_verbs);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004857
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004858 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02004859 spec->input_mux = &spec->private_imux[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004860
Takashi Iwai4a79ba32009-04-22 16:31:35 +02004861 alc_ssid_check(codec, 0x15, 0x1b, 0x14);
4862
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004863 return 1;
4864}
4865
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004866/* additional initialization for auto-configuration model */
4867static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004868{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004869 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004870 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004871 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004872 alc880_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004873 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02004874 alc_inithook(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004875}
4876
Takashi Iwaib59bdf32009-08-11 09:47:30 +02004877/* check the ADC/MUX contains all input pins; some ADC/MUX contains only
4878 * one of two digital mic pins, e.g. on ALC272
4879 */
4880static void fixup_automic_adc(struct hda_codec *codec)
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004881{
Takashi Iwaib59bdf32009-08-11 09:47:30 +02004882 struct alc_spec *spec = codec->spec;
4883 int i;
4884
4885 for (i = 0; i < spec->num_adc_nids; i++) {
4886 hda_nid_t cap = spec->capsrc_nids ?
4887 spec->capsrc_nids[i] : spec->adc_nids[i];
4888 int iidx, eidx;
4889
4890 iidx = get_connection_index(codec, cap, spec->int_mic.pin);
4891 if (iidx < 0)
4892 continue;
4893 eidx = get_connection_index(codec, cap, spec->ext_mic.pin);
4894 if (eidx < 0)
4895 continue;
4896 spec->int_mic.mux_idx = iidx;
4897 spec->ext_mic.mux_idx = eidx;
4898 if (spec->capsrc_nids)
4899 spec->capsrc_nids += i;
4900 spec->adc_nids += i;
4901 spec->num_adc_nids = 1;
4902 return;
4903 }
4904 snd_printd(KERN_INFO "hda_codec: %s: "
4905 "No ADC/MUX containing both 0x%x and 0x%x pins\n",
4906 codec->chip_name, spec->int_mic.pin, spec->ext_mic.pin);
4907 spec->auto_mic = 0; /* disable auto-mic to be sure */
4908}
4909
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01004910/* choose the ADC/MUX containing the input pin and initialize the setup */
4911static void fixup_single_adc(struct hda_codec *codec)
4912{
4913 struct alc_spec *spec = codec->spec;
4914 hda_nid_t pin;
4915 int i;
4916
4917 /* search for the input pin; there must be only one */
4918 for (i = 0; i < AUTO_PIN_LAST; i++) {
4919 if (spec->autocfg.input_pins[i]) {
4920 pin = spec->autocfg.input_pins[i];
4921 break;
4922 }
4923 }
4924 if (!pin)
4925 return;
4926
4927 /* set the default connection to that pin */
4928 for (i = 0; i < spec->num_adc_nids; i++) {
4929 hda_nid_t cap = spec->capsrc_nids ?
4930 spec->capsrc_nids[i] : spec->adc_nids[i];
4931 int idx;
4932
4933 idx = get_connection_index(codec, cap, pin);
4934 if (idx < 0)
4935 continue;
4936 /* use only this ADC */
4937 if (spec->capsrc_nids)
4938 spec->capsrc_nids += i;
4939 spec->adc_nids += i;
4940 spec->num_adc_nids = 1;
4941 /* select or unmute this route */
4942 if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
4943 snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
4944 HDA_AMP_MUTE, 0);
4945 } else {
4946 snd_hda_codec_write_cache(codec, cap, 0,
4947 AC_VERB_SET_CONNECT_SEL, idx);
4948 }
4949 return;
4950 }
4951}
4952
Takashi Iwaib59bdf32009-08-11 09:47:30 +02004953static void set_capture_mixer(struct hda_codec *codec)
4954{
4955 struct alc_spec *spec = codec->spec;
Takashi Iwaia23b6882009-03-23 15:21:36 +01004956 static struct snd_kcontrol_new *caps[2][3] = {
4957 { alc_capture_mixer_nosrc1,
4958 alc_capture_mixer_nosrc2,
4959 alc_capture_mixer_nosrc3 },
4960 { alc_capture_mixer1,
4961 alc_capture_mixer2,
4962 alc_capture_mixer3 },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004963 };
Takashi Iwaia23b6882009-03-23 15:21:36 +01004964 if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01004965 int mux = 0;
4966 if (spec->auto_mic)
Takashi Iwaib59bdf32009-08-11 09:47:30 +02004967 fixup_automic_adc(codec);
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01004968 else if (spec->input_mux) {
4969 if (spec->input_mux->num_items > 1)
4970 mux = 1;
4971 else if (spec->input_mux->num_items == 1)
4972 fixup_single_adc(codec);
4973 }
Takashi Iwaia23b6882009-03-23 15:21:36 +01004974 spec->cap_mixer = caps[mux][spec->num_adc_nids - 1];
4975 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004976}
4977
Takashi Iwai67d634c2009-11-16 15:35:59 +01004978#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004979#define set_beep_amp(spec, nid, idx, dir) \
4980 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
Takashi Iwai67d634c2009-11-16 15:35:59 +01004981#else
4982#define set_beep_amp(spec, nid, idx, dir) /* NOP */
4983#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004984
4985/*
4986 * OK, here we have finally the patch for ALC880
4987 */
4988
Linus Torvalds1da177e2005-04-16 15:20:36 -07004989static int patch_alc880(struct hda_codec *codec)
4990{
4991 struct alc_spec *spec;
4992 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01004993 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004994
Takashi Iwaie560d8d2005-09-09 14:21:46 +02004995 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004996 if (spec == NULL)
4997 return -ENOMEM;
4998
4999 codec->spec = spec;
5000
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005001 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
5002 alc880_models,
5003 alc880_cfg_tbl);
5004 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02005005 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
5006 codec->chip_name);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005007 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005008 }
5009
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005010 if (board_config == ALC880_AUTO) {
5011 /* automatic parse from the BIOS config */
5012 err = alc880_parse_auto_config(codec);
5013 if (err < 0) {
5014 alc_free(codec);
5015 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005016 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005017 printk(KERN_INFO
5018 "hda_codec: Cannot set up configuration "
5019 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005020 board_config = ALC880_3ST;
5021 }
5022 }
5023
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09005024 err = snd_hda_attach_beep_device(codec, 0x1);
5025 if (err < 0) {
5026 alc_free(codec);
5027 return err;
5028 }
5029
Kailang Yangdf694da2005-12-05 19:42:22 +01005030 if (board_config != ALC880_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02005031 setup_preset(codec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005032
Linus Torvalds1da177e2005-04-16 15:20:36 -07005033 spec->stream_analog_playback = &alc880_pcm_analog_playback;
5034 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01005035 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005036
Linus Torvalds1da177e2005-04-16 15:20:36 -07005037 spec->stream_digital_playback = &alc880_pcm_digital_playback;
5038 spec->stream_digital_capture = &alc880_pcm_digital_capture;
5039
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005040 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005041 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01005042 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005043 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +02005044 wcap = get_wcaps_type(wcap);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005045 if (wcap != AC_WID_AUD_IN) {
5046 spec->adc_nids = alc880_adc_nids_alt;
5047 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005048 } else {
5049 spec->adc_nids = alc880_adc_nids;
5050 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005051 }
5052 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005053 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005054 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005055
Takashi Iwai2134ea42008-01-10 16:53:55 +01005056 spec->vmaster_nid = 0x0c;
5057
Linus Torvalds1da177e2005-04-16 15:20:36 -07005058 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005059 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005060 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02005061#ifdef CONFIG_SND_HDA_POWER_SAVE
5062 if (!spec->loopback.amplist)
5063 spec->loopback.amplist = alc880_loopbacks;
5064#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005065
5066 return 0;
5067}
5068
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005069
Linus Torvalds1da177e2005-04-16 15:20:36 -07005070/*
5071 * ALC260 support
5072 */
5073
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005074static hda_nid_t alc260_dac_nids[1] = {
5075 /* front */
5076 0x02,
5077};
5078
5079static hda_nid_t alc260_adc_nids[1] = {
5080 /* ADC0 */
5081 0x04,
5082};
5083
Kailang Yangdf694da2005-12-05 19:42:22 +01005084static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005085 /* ADC1 */
5086 0x05,
5087};
5088
Jonathan Woithed57fdac2006-02-28 11:38:35 +01005089/* NIDs used when simultaneous access to both ADCs makes sense. Note that
5090 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
5091 */
5092static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005093 /* ADC0, ADC1 */
5094 0x04, 0x05
5095};
5096
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005097#define ALC260_DIGOUT_NID 0x03
5098#define ALC260_DIGIN_NID 0x06
5099
5100static struct hda_input_mux alc260_capture_source = {
5101 .num_items = 4,
5102 .items = {
5103 { "Mic", 0x0 },
5104 { "Front Mic", 0x1 },
5105 { "Line", 0x2 },
5106 { "CD", 0x4 },
5107 },
5108};
5109
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01005110/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005111 * headphone jack and the internal CD lines since these are the only pins at
5112 * which audio can appear. For flexibility, also allow the option of
5113 * recording the mixer output on the second ADC (ADC0 doesn't have a
5114 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005115 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005116static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
5117 {
5118 .num_items = 3,
5119 .items = {
5120 { "Mic/Line", 0x0 },
5121 { "CD", 0x4 },
5122 { "Headphone", 0x2 },
5123 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005124 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005125 {
5126 .num_items = 4,
5127 .items = {
5128 { "Mic/Line", 0x0 },
5129 { "CD", 0x4 },
5130 { "Headphone", 0x2 },
5131 { "Mixer", 0x5 },
5132 },
5133 },
5134
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005135};
5136
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005137/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
5138 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005139 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005140static struct hda_input_mux alc260_acer_capture_sources[2] = {
5141 {
5142 .num_items = 4,
5143 .items = {
5144 { "Mic", 0x0 },
5145 { "Line", 0x2 },
5146 { "CD", 0x4 },
5147 { "Headphone", 0x5 },
5148 },
5149 },
5150 {
5151 .num_items = 5,
5152 .items = {
5153 { "Mic", 0x0 },
5154 { "Line", 0x2 },
5155 { "CD", 0x4 },
5156 { "Headphone", 0x6 },
5157 { "Mixer", 0x5 },
5158 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005159 },
5160};
Michael Schwingencc959482009-02-22 18:58:45 +01005161
5162/* Maxdata Favorit 100XS */
5163static struct hda_input_mux alc260_favorit100_capture_sources[2] = {
5164 {
5165 .num_items = 2,
5166 .items = {
5167 { "Line/Mic", 0x0 },
5168 { "CD", 0x4 },
5169 },
5170 },
5171 {
5172 .num_items = 3,
5173 .items = {
5174 { "Line/Mic", 0x0 },
5175 { "CD", 0x4 },
5176 { "Mixer", 0x5 },
5177 },
5178 },
5179};
5180
Linus Torvalds1da177e2005-04-16 15:20:36 -07005181/*
5182 * This is just place-holder, so there's something for alc_build_pcms to look
5183 * at when it calculates the maximum number of channels. ALC260 has no mixer
5184 * element which allows changing the channel mode, so the verb list is
5185 * never used.
5186 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01005187static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005188 { 2, NULL },
5189};
5190
Kailang Yangdf694da2005-12-05 19:42:22 +01005191
5192/* Mixer combinations
5193 *
5194 * basic: base_output + input + pc_beep + capture
5195 * HP: base_output + input + capture_alt
5196 * HP_3013: hp_3013 + input + capture
5197 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005198 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01005199 */
5200
5201static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02005202 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005203 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01005204 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5205 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
5206 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5207 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5208 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005209};
Kailang Yangdf694da2005-12-05 19:42:22 +01005210
5211static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005212 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5213 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5214 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5215 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5216 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5217 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5218 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
5219 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005220 { } /* end */
5221};
5222
Takashi Iwaibec15c32008-01-28 18:16:30 +01005223/* update HP, line and mono out pins according to the master switch */
5224static void alc260_hp_master_update(struct hda_codec *codec,
5225 hda_nid_t hp, hda_nid_t line,
5226 hda_nid_t mono)
5227{
5228 struct alc_spec *spec = codec->spec;
5229 unsigned int val = spec->master_sw ? PIN_HP : 0;
5230 /* change HP and line-out pins */
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005231 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005232 val);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005233 snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005234 val);
5235 /* mono (speaker) depending on the HP jack sense */
5236 val = (val && !spec->jack_present) ? PIN_OUT : 0;
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005237 snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005238 val);
5239}
5240
5241static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
5242 struct snd_ctl_elem_value *ucontrol)
5243{
5244 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5245 struct alc_spec *spec = codec->spec;
5246 *ucontrol->value.integer.value = spec->master_sw;
5247 return 0;
5248}
5249
5250static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
5251 struct snd_ctl_elem_value *ucontrol)
5252{
5253 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5254 struct alc_spec *spec = codec->spec;
5255 int val = !!*ucontrol->value.integer.value;
5256 hda_nid_t hp, line, mono;
5257
5258 if (val == spec->master_sw)
5259 return 0;
5260 spec->master_sw = val;
5261 hp = (kcontrol->private_value >> 16) & 0xff;
5262 line = (kcontrol->private_value >> 8) & 0xff;
5263 mono = kcontrol->private_value & 0xff;
5264 alc260_hp_master_update(codec, hp, line, mono);
5265 return 1;
5266}
5267
5268static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
5269 {
5270 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5271 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01005272 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005273 .info = snd_ctl_boolean_mono_info,
5274 .get = alc260_hp_master_sw_get,
5275 .put = alc260_hp_master_sw_put,
5276 .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
5277 },
5278 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5279 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
5280 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5281 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
5282 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
5283 HDA_OUTPUT),
5284 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5285 { } /* end */
5286};
5287
5288static struct hda_verb alc260_hp_unsol_verbs[] = {
5289 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5290 {},
5291};
5292
5293static void alc260_hp_automute(struct hda_codec *codec)
5294{
5295 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01005296
Wu Fengguang864f92b2009-11-18 12:38:02 +08005297 spec->jack_present = snd_hda_jack_detect(codec, 0x10);
Takashi Iwaibec15c32008-01-28 18:16:30 +01005298 alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
5299}
5300
5301static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
5302{
5303 if ((res >> 26) == ALC880_HP_EVENT)
5304 alc260_hp_automute(codec);
5305}
5306
Kailang Yangdf694da2005-12-05 19:42:22 +01005307static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01005308 {
5309 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5310 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01005311 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005312 .info = snd_ctl_boolean_mono_info,
5313 .get = alc260_hp_master_sw_get,
5314 .put = alc260_hp_master_sw_put,
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005315 .private_value = (0x15 << 16) | (0x10 << 8) | 0x11
Takashi Iwaibec15c32008-01-28 18:16:30 +01005316 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005317 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5318 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
5319 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
5320 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
5321 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5322 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01005323 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5324 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02005325 { } /* end */
5326};
5327
Kailang Yang3f878302008-08-26 13:02:23 +02005328static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
5329 .ops = &snd_hda_bind_vol,
5330 .values = {
5331 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
5332 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
5333 HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
5334 0
5335 },
5336};
5337
5338static struct hda_bind_ctls alc260_dc7600_bind_switch = {
5339 .ops = &snd_hda_bind_sw,
5340 .values = {
5341 HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
5342 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
5343 0
5344 },
5345};
5346
5347static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
5348 HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
5349 HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
5350 HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
5351 HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
5352 { } /* end */
5353};
5354
Takashi Iwaibec15c32008-01-28 18:16:30 +01005355static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
5356 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5357 {},
5358};
5359
5360static void alc260_hp_3013_automute(struct hda_codec *codec)
5361{
5362 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01005363
Wu Fengguang864f92b2009-11-18 12:38:02 +08005364 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005365 alc260_hp_master_update(codec, 0x15, 0x10, 0x11);
Takashi Iwaibec15c32008-01-28 18:16:30 +01005366}
5367
5368static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
5369 unsigned int res)
5370{
5371 if ((res >> 26) == ALC880_HP_EVENT)
5372 alc260_hp_3013_automute(codec);
5373}
5374
Kailang Yang3f878302008-08-26 13:02:23 +02005375static void alc260_hp_3012_automute(struct hda_codec *codec)
5376{
Wu Fengguang864f92b2009-11-18 12:38:02 +08005377 unsigned int bits = snd_hda_jack_detect(codec, 0x10) ? 0 : PIN_OUT;
Kailang Yang3f878302008-08-26 13:02:23 +02005378
Kailang Yang3f878302008-08-26 13:02:23 +02005379 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5380 bits);
5381 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5382 bits);
5383 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5384 bits);
5385}
5386
5387static void alc260_hp_3012_unsol_event(struct hda_codec *codec,
5388 unsigned int res)
5389{
5390 if ((res >> 26) == ALC880_HP_EVENT)
5391 alc260_hp_3012_automute(codec);
5392}
5393
5394/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005395 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
5396 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01005397static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005398 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005399 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005400 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005401 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5402 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5403 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
5404 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005405 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01005406 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5407 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01005408 { } /* end */
5409};
5410
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005411/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
5412 * versions of the ALC260 don't act on requests to enable mic bias from NID
5413 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
5414 * datasheet doesn't mention this restriction. At this stage it's not clear
5415 * whether this behaviour is intentional or is a hardware bug in chip
5416 * revisions available in early 2006. Therefore for now allow the
5417 * "Headphone Jack Mode" control to span all choices, but if it turns out
5418 * that the lack of mic bias for this NID is intentional we could change the
5419 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
5420 *
5421 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
5422 * don't appear to make the mic bias available from the "line" jack, even
5423 * though the NID used for this jack (0x14) can supply it. The theory is
5424 * that perhaps Acer have included blocking capacitors between the ALC260
5425 * and the output jack. If this turns out to be the case for all such
5426 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
5427 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01005428 *
5429 * The C20x Tablet series have a mono internal speaker which is controlled
5430 * via the chip's Mono sum widget and pin complex, so include the necessary
5431 * controls for such models. On models without a "mono speaker" the control
5432 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005433 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005434static struct snd_kcontrol_new alc260_acer_mixer[] = {
5435 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5436 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005437 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01005438 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01005439 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01005440 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01005441 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005442 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5443 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5444 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5445 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5446 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5447 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5448 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5449 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005450 { } /* end */
5451};
5452
Michael Schwingencc959482009-02-22 18:58:45 +01005453/* Maxdata Favorit 100XS: one output and one input (0x12) jack
5454 */
5455static struct snd_kcontrol_new alc260_favorit100_mixer[] = {
5456 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5457 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
5458 ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
5459 HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5460 HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5461 ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5462 { } /* end */
5463};
5464
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005465/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
5466 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
5467 */
5468static struct snd_kcontrol_new alc260_will_mixer[] = {
5469 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5470 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
5471 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5472 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5473 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5474 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5475 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5476 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
5477 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5478 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005479 { } /* end */
5480};
5481
5482/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
5483 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
5484 */
5485static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
5486 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5487 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
5488 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5489 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5490 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5491 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
5492 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
5493 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5494 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5495 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
5496 { } /* end */
5497};
5498
Kailang Yangdf694da2005-12-05 19:42:22 +01005499/*
5500 * initialization verbs
5501 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005502static struct hda_verb alc260_init_verbs[] = {
5503 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005504 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005505 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005506 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005507 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005508 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005510 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005511 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02005512 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01005514 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02005516 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005517 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02005518 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005519 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02005520 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5521 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02005522 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005523 /* set connection select to line in (default select for this ADC) */
5524 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02005525 /* mute capture amp left and right */
5526 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5527 /* set connection select to line in (default select for this ADC) */
5528 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02005529 /* set vol=0 Line-Out mixer amp left and right */
5530 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5531 /* unmute pin widget amp left and right (no gain on this amp) */
5532 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5533 /* set vol=0 HP mixer amp left and right */
5534 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5535 /* unmute pin widget amp left and right (no gain on this amp) */
5536 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5537 /* set vol=0 Mono mixer amp left and right */
5538 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5539 /* unmute pin widget amp left and right (no gain on this amp) */
5540 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5541 /* unmute LINE-2 out pin */
5542 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005543 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
5544 * Line In 2 = 0x03
5545 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005546 /* mute analog inputs */
5547 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5548 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5549 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5550 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5551 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005552 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005553 /* mute Front out path */
5554 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5555 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5556 /* mute Headphone out path */
5557 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5558 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5559 /* mute Mono out path */
5560 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5561 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562 { }
5563};
5564
Takashi Iwai474167d2006-05-17 17:17:43 +02005565#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01005566static struct hda_verb alc260_hp_init_verbs[] = {
5567 /* Headphone and output */
5568 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
5569 /* mono output */
5570 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5571 /* Mic1 (rear panel) pin widget for input and vref at 80% */
5572 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5573 /* Mic2 (front panel) pin widget for input and vref at 80% */
5574 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5575 /* Line In pin widget for input */
5576 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5577 /* Line-2 pin widget for output */
5578 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5579 /* CD pin widget for input */
5580 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5581 /* unmute amp left and right */
5582 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
5583 /* set connection select to line in (default select for this ADC) */
5584 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
5585 /* unmute Line-Out mixer amp left and right (volume = 0) */
5586 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5587 /* mute pin widget amp left and right (no gain on this amp) */
5588 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
5589 /* unmute HP mixer amp left and right (volume = 0) */
5590 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5591 /* mute pin widget amp left and right (no gain on this amp) */
5592 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005593 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
5594 * Line In 2 = 0x03
5595 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005596 /* mute analog inputs */
5597 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5598 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5599 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5600 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5601 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005602 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
5603 /* Unmute Front out path */
5604 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5605 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5606 /* Unmute Headphone out path */
5607 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5608 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5609 /* Unmute Mono out path */
5610 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5611 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5612 { }
5613};
Takashi Iwai474167d2006-05-17 17:17:43 +02005614#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01005615
5616static struct hda_verb alc260_hp_3013_init_verbs[] = {
5617 /* Line out and output */
5618 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5619 /* mono output */
5620 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5621 /* Mic1 (rear panel) pin widget for input and vref at 80% */
5622 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5623 /* Mic2 (front panel) pin widget for input and vref at 80% */
5624 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5625 /* Line In pin widget for input */
5626 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5627 /* Headphone pin widget for output */
5628 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
5629 /* CD pin widget for input */
5630 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5631 /* unmute amp left and right */
5632 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
5633 /* set connection select to line in (default select for this ADC) */
5634 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
5635 /* unmute Line-Out mixer amp left and right (volume = 0) */
5636 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5637 /* mute pin widget amp left and right (no gain on this amp) */
5638 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
5639 /* unmute HP mixer amp left and right (volume = 0) */
5640 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5641 /* mute pin widget amp left and right (no gain on this amp) */
5642 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005643 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
5644 * Line In 2 = 0x03
5645 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005646 /* mute analog inputs */
5647 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5648 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5649 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5650 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5651 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005652 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
5653 /* Unmute Front out path */
5654 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5655 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5656 /* Unmute Headphone out path */
5657 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5658 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5659 /* Unmute Mono out path */
5660 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5661 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5662 { }
5663};
5664
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005665/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005666 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
5667 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005668 */
5669static struct hda_verb alc260_fujitsu_init_verbs[] = {
5670 /* Disable all GPIOs */
5671 {0x01, AC_VERB_SET_GPIO_MASK, 0},
5672 /* Internal speaker is connected to headphone pin */
5673 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5674 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
5675 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005676 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
5677 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
5678 /* Ensure all other unused pins are disabled and muted. */
5679 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5680 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005681 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005682 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005683 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005684 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5685 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5686 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005687
Jonathan Woithef7ace402006-02-28 11:46:14 +01005688 /* Disable digital (SPDIF) pins */
5689 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5690 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005691
Kailang Yangea1fb292008-08-26 12:58:38 +02005692 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
Jonathan Woithef7ace402006-02-28 11:46:14 +01005693 * when acting as an output.
5694 */
5695 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5696
5697 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01005698 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5699 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5700 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5701 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5702 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5703 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5704 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5705 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5706 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005707
Jonathan Woithef7ace402006-02-28 11:46:14 +01005708 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
5709 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5710 /* Unmute Line1 pin widget output buffer since it starts as an output.
5711 * If the pin mode is changed by the user the pin mode control will
5712 * take care of enabling the pin's input/output buffers as needed.
5713 * Therefore there's no need to enable the input buffer at this
5714 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01005715 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01005716 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +02005717 /* Unmute input buffer of pin widget used for Line-in (no equiv
Jonathan Woithecdcd9262006-02-28 11:36:42 +01005718 * mixer ctrl)
5719 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01005720 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005721
Jonathan Woithef7ace402006-02-28 11:46:14 +01005722 /* Mute capture amp left and right */
5723 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02005724 /* Set ADC connection select to match default mixer setting - line
Jonathan Woithef7ace402006-02-28 11:46:14 +01005725 * in (on mic1 pin)
5726 */
5727 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005728
Jonathan Woithef7ace402006-02-28 11:46:14 +01005729 /* Do the same for the second ADC: mute capture input amp and
5730 * set ADC connection to line in (on mic1 pin)
5731 */
5732 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5733 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005734
Jonathan Woithef7ace402006-02-28 11:46:14 +01005735 /* Mute all inputs to mixer widget (even unconnected ones) */
5736 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5737 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5738 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5739 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5740 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5741 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5742 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5743 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01005744
5745 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005746};
5747
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005748/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
5749 * similar laptops (adapted from Fujitsu init verbs).
5750 */
5751static struct hda_verb alc260_acer_init_verbs[] = {
5752 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
5753 * the headphone jack. Turn this on and rely on the standard mute
5754 * methods whenever the user wants to turn these outputs off.
5755 */
5756 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
5757 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
5758 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
5759 /* Internal speaker/Headphone jack is connected to Line-out pin */
5760 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5761 /* Internal microphone/Mic jack is connected to Mic1 pin */
5762 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
5763 /* Line In jack is connected to Line1 pin */
5764 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01005765 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
5766 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005767 /* Ensure all other unused pins are disabled and muted. */
5768 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5769 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005770 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5771 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5772 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5773 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5774 /* Disable digital (SPDIF) pins */
5775 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5776 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
5777
Kailang Yangea1fb292008-08-26 12:58:38 +02005778 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005779 * bus when acting as outputs.
5780 */
5781 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
5782 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5783
5784 /* Start with output sum widgets muted and their output gains at min */
5785 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5786 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5787 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5788 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5789 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5790 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5791 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5792 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5793 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5794
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005795 /* Unmute Line-out pin widget amp left and right
5796 * (no equiv mixer ctrl)
5797 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005798 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01005799 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
5800 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005801 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
5802 * inputs. If the pin mode is changed by the user the pin mode control
5803 * will take care of enabling the pin's input/output buffers as needed.
5804 * Therefore there's no need to enable the input buffer at this
5805 * stage.
5806 */
5807 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5808 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5809
5810 /* Mute capture amp left and right */
5811 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5812 /* Set ADC connection select to match default mixer setting - mic
5813 * (on mic1 pin)
5814 */
5815 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5816
5817 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005818 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005819 */
5820 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005821 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005822
5823 /* Mute all inputs to mixer widget (even unconnected ones) */
5824 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5825 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5826 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5827 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5828 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5829 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5830 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5831 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
5832
5833 { }
5834};
5835
Michael Schwingencc959482009-02-22 18:58:45 +01005836/* Initialisation sequence for Maxdata Favorit 100XS
5837 * (adapted from Acer init verbs).
5838 */
5839static struct hda_verb alc260_favorit100_init_verbs[] = {
5840 /* GPIO 0 enables the output jack.
5841 * Turn this on and rely on the standard mute
5842 * methods whenever the user wants to turn these outputs off.
5843 */
5844 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
5845 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
5846 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
5847 /* Line/Mic input jack is connected to Mic1 pin */
5848 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
5849 /* Ensure all other unused pins are disabled and muted. */
5850 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5851 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5852 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5853 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5854 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5855 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5856 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5857 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5858 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5859 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5860 /* Disable digital (SPDIF) pins */
5861 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5862 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
5863
5864 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
5865 * bus when acting as outputs.
5866 */
5867 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
5868 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5869
5870 /* Start with output sum widgets muted and their output gains at min */
5871 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5872 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5873 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5874 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5875 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5876 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5877 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5878 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5879 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5880
5881 /* Unmute Line-out pin widget amp left and right
5882 * (no equiv mixer ctrl)
5883 */
5884 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5885 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
5886 * inputs. If the pin mode is changed by the user the pin mode control
5887 * will take care of enabling the pin's input/output buffers as needed.
5888 * Therefore there's no need to enable the input buffer at this
5889 * stage.
5890 */
5891 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5892
5893 /* Mute capture amp left and right */
5894 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5895 /* Set ADC connection select to match default mixer setting - mic
5896 * (on mic1 pin)
5897 */
5898 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5899
5900 /* Do similar with the second ADC: mute capture input amp and
5901 * set ADC connection to mic to match ALSA's default state.
5902 */
5903 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5904 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
5905
5906 /* Mute all inputs to mixer widget (even unconnected ones) */
5907 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5908 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5909 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5910 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5911 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5912 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5913 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5914 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
5915
5916 { }
5917};
5918
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005919static struct hda_verb alc260_will_verbs[] = {
5920 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5921 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
5922 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
5923 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
5924 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
5925 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
5926 {}
5927};
5928
5929static struct hda_verb alc260_replacer_672v_verbs[] = {
5930 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
5931 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
5932 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
5933
5934 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
5935 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
5936 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
5937
5938 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5939 {}
5940};
5941
5942/* toggle speaker-output according to the hp-jack state */
5943static void alc260_replacer_672v_automute(struct hda_codec *codec)
5944{
5945 unsigned int present;
5946
5947 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
Wu Fengguang864f92b2009-11-18 12:38:02 +08005948 present = snd_hda_jack_detect(codec, 0x0f);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005949 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005950 snd_hda_codec_write_cache(codec, 0x01, 0,
5951 AC_VERB_SET_GPIO_DATA, 1);
5952 snd_hda_codec_write_cache(codec, 0x0f, 0,
5953 AC_VERB_SET_PIN_WIDGET_CONTROL,
5954 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005955 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005956 snd_hda_codec_write_cache(codec, 0x01, 0,
5957 AC_VERB_SET_GPIO_DATA, 0);
5958 snd_hda_codec_write_cache(codec, 0x0f, 0,
5959 AC_VERB_SET_PIN_WIDGET_CONTROL,
5960 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005961 }
5962}
5963
5964static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
5965 unsigned int res)
5966{
5967 if ((res >> 26) == ALC880_HP_EVENT)
5968 alc260_replacer_672v_automute(codec);
5969}
5970
Kailang Yang3f878302008-08-26 13:02:23 +02005971static struct hda_verb alc260_hp_dc7600_verbs[] = {
5972 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
5973 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
5974 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5975 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5976 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5977 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5978 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5979 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5980 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5981 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5982 {}
5983};
5984
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005985/* Test configuration for debugging, modelled after the ALC880 test
5986 * configuration.
5987 */
5988#ifdef CONFIG_SND_DEBUG
5989static hda_nid_t alc260_test_dac_nids[1] = {
5990 0x02,
5991};
5992static hda_nid_t alc260_test_adc_nids[2] = {
5993 0x04, 0x05,
5994};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005995/* For testing the ALC260, each input MUX needs its own definition since
Kailang Yangea1fb292008-08-26 12:58:38 +02005996 * the signal assignments are different. This assumes that the first ADC
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005997 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01005998 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005999static struct hda_input_mux alc260_test_capture_sources[2] = {
6000 {
6001 .num_items = 7,
6002 .items = {
6003 { "MIC1 pin", 0x0 },
6004 { "MIC2 pin", 0x1 },
6005 { "LINE1 pin", 0x2 },
6006 { "LINE2 pin", 0x3 },
6007 { "CD pin", 0x4 },
6008 { "LINE-OUT pin", 0x5 },
6009 { "HP-OUT pin", 0x6 },
6010 },
6011 },
6012 {
6013 .num_items = 8,
6014 .items = {
6015 { "MIC1 pin", 0x0 },
6016 { "MIC2 pin", 0x1 },
6017 { "LINE1 pin", 0x2 },
6018 { "LINE2 pin", 0x3 },
6019 { "CD pin", 0x4 },
6020 { "Mixer", 0x5 },
6021 { "LINE-OUT pin", 0x6 },
6022 { "HP-OUT pin", 0x7 },
6023 },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006024 },
6025};
6026static struct snd_kcontrol_new alc260_test_mixer[] = {
6027 /* Output driver widgets */
6028 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
6029 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
6030 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6031 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
6032 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6033 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
6034
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006035 /* Modes for retasking pin widgets
6036 * Note: the ALC260 doesn't seem to act on requests to enable mic
6037 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
6038 * mention this restriction. At this stage it's not clear whether
6039 * this behaviour is intentional or is a hardware bug in chip
6040 * revisions available at least up until early 2006. Therefore for
6041 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
6042 * choices, but if it turns out that the lack of mic bias for these
6043 * NIDs is intentional we could change their modes from
6044 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
6045 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006046 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
6047 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
6048 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
6049 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
6050 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
6051 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
6052
6053 /* Loopback mixer controls */
6054 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
6055 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
6056 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
6057 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
6058 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
6059 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
6060 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
6061 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
6062 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6063 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006064 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
6065 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
6066 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
6067 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01006068
6069 /* Controls for GPIO pins, assuming they are configured as outputs */
6070 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
6071 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
6072 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
6073 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
6074
Jonathan Woithe92621f12006-02-28 11:47:47 +01006075 /* Switches to allow the digital IO pins to be enabled. The datasheet
6076 * is ambigious as to which NID is which; testing on laptops which
Kailang Yangea1fb292008-08-26 12:58:38 +02006077 * make this output available should provide clarification.
Jonathan Woithe92621f12006-02-28 11:47:47 +01006078 */
6079 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
6080 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
6081
Jonathan Woithef8225f62008-01-08 12:16:54 +01006082 /* A switch allowing EAPD to be enabled. Some laptops seem to use
6083 * this output to turn on an external amplifier.
6084 */
6085 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
6086 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
6087
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006088 { } /* end */
6089};
6090static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01006091 /* Enable all GPIOs as outputs with an initial value of 0 */
6092 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
6093 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6094 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
6095
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006096 /* Enable retasking pins as output, initially without power amp */
6097 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6098 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6099 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6100 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6101 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6102 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6103
Jonathan Woithe92621f12006-02-28 11:47:47 +01006104 /* Disable digital (SPDIF) pins initially, but users can enable
6105 * them via a mixer switch. In the case of SPDIF-out, this initverb
6106 * payload also sets the generation to 0, output to be in "consumer"
6107 * PCM format, copyright asserted, no pre-emphasis and no validity
6108 * control.
6109 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006110 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6111 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6112
Kailang Yangea1fb292008-08-26 12:58:38 +02006113 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006114 * OUT1 sum bus when acting as an output.
6115 */
6116 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6117 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
6118 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6119 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
6120
6121 /* Start with output sum widgets muted and their output gains at min */
6122 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6123 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6124 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6125 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6126 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6127 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6128 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6129 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6130 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6131
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006132 /* Unmute retasking pin widget output buffers since the default
6133 * state appears to be output. As the pin mode is changed by the
6134 * user the pin mode control will take care of enabling the pin's
6135 * input/output buffers as needed.
6136 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006137 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6138 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6139 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6140 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6141 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6142 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6143 /* Also unmute the mono-out pin widget */
6144 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6145
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006146 /* Mute capture amp left and right */
6147 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006148 /* Set ADC connection select to match default mixer setting (mic1
6149 * pin)
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006150 */
6151 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6152
6153 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01006154 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006155 */
6156 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6157 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6158
6159 /* Mute all inputs to mixer widget (even unconnected ones) */
6160 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6161 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6162 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6163 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6164 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6165 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6166 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6167 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6168
6169 { }
6170};
6171#endif
6172
Takashi Iwai63300792008-01-24 15:31:36 +01006173#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
6174#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07006175
Takashi Iwaia3bcba32005-12-06 19:05:29 +01006176#define alc260_pcm_digital_playback alc880_pcm_digital_playback
6177#define alc260_pcm_digital_capture alc880_pcm_digital_capture
6178
Kailang Yangdf694da2005-12-05 19:42:22 +01006179/*
6180 * for BIOS auto-configuration
6181 */
6182
6183static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai863b4512008-10-21 17:01:47 +02006184 const char *pfx, int *vol_bits)
Kailang Yangdf694da2005-12-05 19:42:22 +01006185{
6186 hda_nid_t nid_vol;
6187 unsigned long vol_val, sw_val;
Kailang Yangdf694da2005-12-05 19:42:22 +01006188 int err;
6189
6190 if (nid >= 0x0f && nid < 0x11) {
6191 nid_vol = nid - 0x7;
6192 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
6193 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
6194 } else if (nid == 0x11) {
6195 nid_vol = nid - 0x7;
6196 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
6197 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
6198 } else if (nid >= 0x12 && nid <= 0x15) {
6199 nid_vol = 0x08;
6200 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
6201 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
6202 } else
6203 return 0; /* N/A */
Kailang Yangea1fb292008-08-26 12:58:38 +02006204
Takashi Iwai863b4512008-10-21 17:01:47 +02006205 if (!(*vol_bits & (1 << nid_vol))) {
6206 /* first control for the volume widget */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02006207 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, vol_val);
Takashi Iwai863b4512008-10-21 17:01:47 +02006208 if (err < 0)
6209 return err;
6210 *vol_bits |= (1 << nid_vol);
6211 }
Takashi Iwai0afe5f82009-10-02 09:20:00 +02006212 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, sw_val);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006213 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006214 return err;
6215 return 1;
6216}
6217
6218/* add playback controls from the parsed DAC table */
6219static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
6220 const struct auto_pin_cfg *cfg)
6221{
6222 hda_nid_t nid;
6223 int err;
Takashi Iwai863b4512008-10-21 17:01:47 +02006224 int vols = 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01006225
6226 spec->multiout.num_dacs = 1;
6227 spec->multiout.dac_nids = spec->private_dac_nids;
6228 spec->multiout.dac_nids[0] = 0x02;
6229
6230 nid = cfg->line_out_pins[0];
6231 if (nid) {
Takashi Iwai23112d62009-08-25 16:07:08 +02006232 const char *pfx;
6233 if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
6234 pfx = "Master";
6235 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
6236 pfx = "Speaker";
6237 else
6238 pfx = "Front";
6239 err = alc260_add_playback_controls(spec, nid, pfx, &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006240 if (err < 0)
6241 return err;
6242 }
6243
Takashi Iwai82bc9552006-03-21 11:24:42 +01006244 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006245 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02006246 err = alc260_add_playback_controls(spec, nid, "Speaker", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006247 if (err < 0)
6248 return err;
6249 }
6250
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006251 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006252 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02006253 err = alc260_add_playback_controls(spec, nid, "Headphone",
6254 &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006255 if (err < 0)
6256 return err;
6257 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006258 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01006259}
6260
6261/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +02006262static int alc260_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yangdf694da2005-12-05 19:42:22 +01006263 const struct auto_pin_cfg *cfg)
6264{
Takashi Iwai05f5f472009-08-25 13:10:18 +02006265 return alc_auto_create_input_ctls(codec, cfg, 0x07, 0x04, 0x05);
Kailang Yangdf694da2005-12-05 19:42:22 +01006266}
6267
6268static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
6269 hda_nid_t nid, int pin_type,
6270 int sel_idx)
6271{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006272 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006273 /* need the manual connection? */
6274 if (nid >= 0x12) {
6275 int idx = nid - 0x12;
6276 snd_hda_codec_write(codec, idx + 0x0b, 0,
6277 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01006278 }
6279}
6280
6281static void alc260_auto_init_multi_out(struct hda_codec *codec)
6282{
6283 struct alc_spec *spec = codec->spec;
6284 hda_nid_t nid;
6285
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006286 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006287 if (nid) {
6288 int pin_type = get_pin_type(spec->autocfg.line_out_type);
6289 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
6290 }
Kailang Yangea1fb292008-08-26 12:58:38 +02006291
Takashi Iwai82bc9552006-03-21 11:24:42 +01006292 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006293 if (nid)
6294 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
6295
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006296 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006297 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006298 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006299}
Kailang Yangdf694da2005-12-05 19:42:22 +01006300
6301#define ALC260_PIN_CD_NID 0x16
6302static void alc260_auto_init_analog_input(struct hda_codec *codec)
6303{
6304 struct alc_spec *spec = codec->spec;
6305 int i;
6306
6307 for (i = 0; i < AUTO_PIN_LAST; i++) {
6308 hda_nid_t nid = spec->autocfg.input_pins[i];
6309 if (nid >= 0x12) {
Takashi Iwai23f0c042009-02-26 13:03:58 +01006310 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +01006311 if (nid != ALC260_PIN_CD_NID &&
6312 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006313 snd_hda_codec_write(codec, nid, 0,
6314 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01006315 AMP_OUT_MUTE);
6316 }
6317 }
6318}
6319
6320/*
6321 * generic initialization of ADC, input mixers and output mixers
6322 */
6323static struct hda_verb alc260_volume_init_verbs[] = {
6324 /*
6325 * Unmute ADC0-1 and set the default input to mic-in
6326 */
6327 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6328 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6329 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6330 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006331
Kailang Yangdf694da2005-12-05 19:42:22 +01006332 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
6333 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006334 * Note: PASD motherboards uses the Line In 2 as the input for
6335 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01006336 */
6337 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006338 /* mute analog inputs */
6339 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6340 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6341 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6342 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6343 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006344
6345 /*
6346 * Set up output mixers (0x08 - 0x0a)
6347 */
6348 /* set vol=0 to output mixers */
6349 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6350 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6351 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6352 /* set up input amps for analog loopback */
6353 /* Amp Indices: DAC = 0, mixer = 1 */
6354 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6355 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6356 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6357 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6358 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6359 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006360
Kailang Yangdf694da2005-12-05 19:42:22 +01006361 { }
6362};
6363
6364static int alc260_parse_auto_config(struct hda_codec *codec)
6365{
6366 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006367 int err;
6368 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
6369
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006370 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
6371 alc260_ignore);
6372 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006373 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006374 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
6375 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01006376 return err;
Takashi Iwai603c4012008-07-30 15:01:44 +02006377 if (!spec->kctls.list)
Kailang Yangdf694da2005-12-05 19:42:22 +01006378 return 0; /* can't find valid BIOS pin config */
Takashi Iwai05f5f472009-08-25 13:10:18 +02006379 err = alc260_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006380 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006381 return err;
6382
6383 spec->multiout.max_channels = 2;
6384
Takashi Iwai0852d7a2009-02-11 11:35:15 +01006385 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +01006386 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
Takashi Iwai603c4012008-07-30 15:01:44 +02006387 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01006388 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +01006389
Takashi Iwaid88897e2008-10-31 15:01:37 +01006390 add_verb(spec, alc260_volume_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +01006391
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006392 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02006393 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006394
Takashi Iwai4a79ba32009-04-22 16:31:35 +02006395 alc_ssid_check(codec, 0x10, 0x15, 0x0f);
6396
Kailang Yangdf694da2005-12-05 19:42:22 +01006397 return 1;
6398}
6399
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006400/* additional initialization for auto-configuration model */
6401static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01006402{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006403 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006404 alc260_auto_init_multi_out(codec);
6405 alc260_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006406 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02006407 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01006408}
6409
Takashi Iwaicb53c622007-08-10 17:21:45 +02006410#ifdef CONFIG_SND_HDA_POWER_SAVE
6411static struct hda_amp_list alc260_loopbacks[] = {
6412 { 0x07, HDA_INPUT, 0 },
6413 { 0x07, HDA_INPUT, 1 },
6414 { 0x07, HDA_INPUT, 2 },
6415 { 0x07, HDA_INPUT, 3 },
6416 { 0x07, HDA_INPUT, 4 },
6417 { } /* end */
6418};
6419#endif
6420
Kailang Yangdf694da2005-12-05 19:42:22 +01006421/*
6422 * ALC260 configurations
6423 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006424static const char *alc260_models[ALC260_MODEL_LAST] = {
6425 [ALC260_BASIC] = "basic",
6426 [ALC260_HP] = "hp",
6427 [ALC260_HP_3013] = "hp-3013",
Takashi Iwai2922c9a2008-08-27 18:12:42 +02006428 [ALC260_HP_DC7600] = "hp-dc7600",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006429 [ALC260_FUJITSU_S702X] = "fujitsu",
6430 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006431 [ALC260_WILL] = "will",
6432 [ALC260_REPLACER_672V] = "replacer",
Michael Schwingencc959482009-02-22 18:58:45 +01006433 [ALC260_FAVORIT100] = "favorit100",
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006434#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006435 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006436#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006437 [ALC260_AUTO] = "auto",
6438};
6439
6440static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01006441 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Daniel T Chen950200e2009-12-13 14:11:02 -05006442 SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006443 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Michael Schwingencc959482009-02-22 18:58:45 +01006444 SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100),
Takashi Iwai9720b712007-03-13 21:46:23 +01006445 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwai4ac55982009-11-10 16:08:45 +01006446 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006447 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
Jaroslav Kysela34ec8a02008-07-10 14:49:19 +02006448 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
Kailang Yang3f878302008-08-26 13:02:23 +02006449 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006450 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
6451 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
6452 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
6453 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
6454 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
6455 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
6456 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
6457 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
6458 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006459 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006460 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02006461 {}
6462};
6463
Kailang Yangdf694da2005-12-05 19:42:22 +01006464static struct alc_config_preset alc260_presets[] = {
6465 [ALC260_BASIC] = {
6466 .mixers = { alc260_base_output_mixer,
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01006467 alc260_input_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01006468 .init_verbs = { alc260_init_verbs },
6469 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6470 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006471 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
Kailang Yangdf694da2005-12-05 19:42:22 +01006472 .adc_nids = alc260_adc_nids,
6473 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6474 .channel_mode = alc260_modes,
6475 .input_mux = &alc260_capture_source,
6476 },
6477 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006478 .mixers = { alc260_hp_output_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006479 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01006480 .init_verbs = { alc260_init_verbs,
6481 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01006482 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6483 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006484 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
6485 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01006486 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6487 .channel_mode = alc260_modes,
6488 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006489 .unsol_event = alc260_hp_unsol_event,
6490 .init_hook = alc260_hp_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01006491 },
Kailang Yang3f878302008-08-26 13:02:23 +02006492 [ALC260_HP_DC7600] = {
6493 .mixers = { alc260_hp_dc7600_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006494 alc260_input_mixer },
Kailang Yang3f878302008-08-26 13:02:23 +02006495 .init_verbs = { alc260_init_verbs,
6496 alc260_hp_dc7600_verbs },
6497 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6498 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006499 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
6500 .adc_nids = alc260_adc_nids_alt,
Kailang Yang3f878302008-08-26 13:02:23 +02006501 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6502 .channel_mode = alc260_modes,
6503 .input_mux = &alc260_capture_source,
6504 .unsol_event = alc260_hp_3012_unsol_event,
6505 .init_hook = alc260_hp_3012_automute,
6506 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006507 [ALC260_HP_3013] = {
6508 .mixers = { alc260_hp_3013_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006509 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01006510 .init_verbs = { alc260_hp_3013_init_verbs,
6511 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01006512 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6513 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006514 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
6515 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01006516 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6517 .channel_mode = alc260_modes,
6518 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006519 .unsol_event = alc260_hp_3013_unsol_event,
6520 .init_hook = alc260_hp_3013_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01006521 },
6522 [ALC260_FUJITSU_S702X] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006523 .mixers = { alc260_fujitsu_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01006524 .init_verbs = { alc260_fujitsu_init_verbs },
6525 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6526 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01006527 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
6528 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01006529 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6530 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006531 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
6532 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01006533 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006534 [ALC260_ACER] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006535 .mixers = { alc260_acer_mixer },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006536 .init_verbs = { alc260_acer_init_verbs },
6537 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6538 .dac_nids = alc260_dac_nids,
6539 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
6540 .adc_nids = alc260_dual_adc_nids,
6541 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6542 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006543 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
6544 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006545 },
Michael Schwingencc959482009-02-22 18:58:45 +01006546 [ALC260_FAVORIT100] = {
6547 .mixers = { alc260_favorit100_mixer },
6548 .init_verbs = { alc260_favorit100_init_verbs },
6549 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6550 .dac_nids = alc260_dac_nids,
6551 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
6552 .adc_nids = alc260_dual_adc_nids,
6553 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6554 .channel_mode = alc260_modes,
6555 .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources),
6556 .input_mux = alc260_favorit100_capture_sources,
6557 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006558 [ALC260_WILL] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006559 .mixers = { alc260_will_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006560 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
6561 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6562 .dac_nids = alc260_dac_nids,
6563 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
6564 .adc_nids = alc260_adc_nids,
6565 .dig_out_nid = ALC260_DIGOUT_NID,
6566 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6567 .channel_mode = alc260_modes,
6568 .input_mux = &alc260_capture_source,
6569 },
6570 [ALC260_REPLACER_672V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006571 .mixers = { alc260_replacer_672v_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006572 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
6573 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6574 .dac_nids = alc260_dac_nids,
6575 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
6576 .adc_nids = alc260_adc_nids,
6577 .dig_out_nid = ALC260_DIGOUT_NID,
6578 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6579 .channel_mode = alc260_modes,
6580 .input_mux = &alc260_capture_source,
6581 .unsol_event = alc260_replacer_672v_unsol_event,
6582 .init_hook = alc260_replacer_672v_automute,
6583 },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006584#ifdef CONFIG_SND_DEBUG
6585 [ALC260_TEST] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006586 .mixers = { alc260_test_mixer },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006587 .init_verbs = { alc260_test_init_verbs },
6588 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
6589 .dac_nids = alc260_test_dac_nids,
6590 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
6591 .adc_nids = alc260_test_adc_nids,
6592 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6593 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006594 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
6595 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006596 },
6597#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01006598};
6599
Linus Torvalds1da177e2005-04-16 15:20:36 -07006600static int patch_alc260(struct hda_codec *codec)
6601{
6602 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006603 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006604
Takashi Iwaie560d8d2005-09-09 14:21:46 +02006605 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006606 if (spec == NULL)
6607 return -ENOMEM;
6608
6609 codec->spec = spec;
6610
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006611 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
6612 alc260_models,
6613 alc260_cfg_tbl);
6614 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02006615 snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai6c627f32009-05-18 12:33:36 +02006616 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +01006617 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02006618 }
6619
Kailang Yangdf694da2005-12-05 19:42:22 +01006620 if (board_config == ALC260_AUTO) {
6621 /* automatic parse from the BIOS config */
6622 err = alc260_parse_auto_config(codec);
6623 if (err < 0) {
6624 alc_free(codec);
6625 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006626 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006627 printk(KERN_INFO
6628 "hda_codec: Cannot set up configuration "
6629 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01006630 board_config = ALC260_BASIC;
6631 }
Takashi Iwai16ded522005-06-10 19:58:24 +02006632 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006633
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09006634 err = snd_hda_attach_beep_device(codec, 0x1);
6635 if (err < 0) {
6636 alc_free(codec);
6637 return err;
6638 }
6639
Kailang Yangdf694da2005-12-05 19:42:22 +01006640 if (board_config != ALC260_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02006641 setup_preset(codec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006642
Linus Torvalds1da177e2005-04-16 15:20:36 -07006643 spec->stream_analog_playback = &alc260_pcm_analog_playback;
6644 spec->stream_analog_capture = &alc260_pcm_analog_capture;
6645
Takashi Iwaia3bcba32005-12-06 19:05:29 +01006646 spec->stream_digital_playback = &alc260_pcm_digital_playback;
6647 spec->stream_digital_capture = &alc260_pcm_digital_capture;
6648
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01006649 if (!spec->adc_nids && spec->input_mux) {
6650 /* check whether NID 0x04 is valid */
6651 unsigned int wcap = get_wcaps(codec, 0x04);
Takashi Iwaia22d5432009-07-27 12:54:26 +02006652 wcap = get_wcaps_type(wcap);
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01006653 /* get type */
6654 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
6655 spec->adc_nids = alc260_adc_nids_alt;
6656 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
6657 } else {
6658 spec->adc_nids = alc260_adc_nids;
6659 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
6660 }
6661 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02006662 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01006663 set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006664
Takashi Iwai2134ea42008-01-10 16:53:55 +01006665 spec->vmaster_nid = 0x08;
6666
Linus Torvalds1da177e2005-04-16 15:20:36 -07006667 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01006668 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006669 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02006670#ifdef CONFIG_SND_HDA_POWER_SAVE
6671 if (!spec->loopback.amplist)
6672 spec->loopback.amplist = alc260_loopbacks;
6673#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006674
6675 return 0;
6676}
6677
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006678
Linus Torvalds1da177e2005-04-16 15:20:36 -07006679/*
Takashi Iwai4953550a2009-06-30 15:28:30 +02006680 * ALC882/883/885/888/889 support
Linus Torvalds1da177e2005-04-16 15:20:36 -07006681 *
6682 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
6683 * configuration. Each pin widget can choose any input DACs and a mixer.
6684 * Each ADC is connected from a mixer of all inputs. This makes possible
6685 * 6-channel independent captures.
6686 *
6687 * In addition, an independent DAC for the multi-playback (not used in this
6688 * driver yet).
6689 */
Kailang Yangdf694da2005-12-05 19:42:22 +01006690#define ALC882_DIGOUT_NID 0x06
6691#define ALC882_DIGIN_NID 0x0a
Takashi Iwai4953550a2009-06-30 15:28:30 +02006692#define ALC883_DIGOUT_NID ALC882_DIGOUT_NID
6693#define ALC883_DIGIN_NID ALC882_DIGIN_NID
6694#define ALC1200_DIGOUT_NID 0x10
6695
Linus Torvalds1da177e2005-04-16 15:20:36 -07006696
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01006697static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006698 { 8, NULL }
6699};
6700
Takashi Iwai4953550a2009-06-30 15:28:30 +02006701/* DACs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006702static hda_nid_t alc882_dac_nids[4] = {
6703 /* front, rear, clfe, rear_surr */
6704 0x02, 0x03, 0x04, 0x05
6705};
Takashi Iwai4953550a2009-06-30 15:28:30 +02006706#define alc883_dac_nids alc882_dac_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07006707
Takashi Iwai4953550a2009-06-30 15:28:30 +02006708/* ADCs */
Kailang Yangdf694da2005-12-05 19:42:22 +01006709#define alc882_adc_nids alc880_adc_nids
6710#define alc882_adc_nids_alt alc880_adc_nids_alt
Takashi Iwai4953550a2009-06-30 15:28:30 +02006711#define alc883_adc_nids alc882_adc_nids_alt
6712static hda_nid_t alc883_adc_nids_alt[1] = { 0x08 };
6713static hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 };
6714#define alc889_adc_nids alc880_adc_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07006715
Takashi Iwaie1406342008-02-11 18:32:32 +01006716static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
6717static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
Takashi Iwai4953550a2009-06-30 15:28:30 +02006718#define alc883_capsrc_nids alc882_capsrc_nids_alt
6719static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
6720#define alc889_capsrc_nids alc882_capsrc_nids
Takashi Iwaie1406342008-02-11 18:32:32 +01006721
Linus Torvalds1da177e2005-04-16 15:20:36 -07006722/* input MUX */
6723/* FIXME: should be a matrix-type input source selection */
6724
6725static struct hda_input_mux alc882_capture_source = {
6726 .num_items = 4,
6727 .items = {
6728 { "Mic", 0x0 },
6729 { "Front Mic", 0x1 },
6730 { "Line", 0x2 },
6731 { "CD", 0x4 },
6732 },
6733};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02006734
Takashi Iwai4953550a2009-06-30 15:28:30 +02006735#define alc883_capture_source alc882_capture_source
6736
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02006737static struct hda_input_mux alc889_capture_source = {
6738 .num_items = 3,
6739 .items = {
6740 { "Front Mic", 0x0 },
6741 { "Mic", 0x3 },
6742 { "Line", 0x2 },
6743 },
6744};
6745
Kacper Szczesniak41d55452009-05-07 12:47:43 +02006746static struct hda_input_mux mb5_capture_source = {
6747 .num_items = 3,
6748 .items = {
6749 { "Mic", 0x1 },
6750 { "Line", 0x2 },
6751 { "CD", 0x4 },
6752 },
6753};
6754
Luke Yelaviche458b1f2010-02-12 16:28:29 +11006755static struct hda_input_mux macmini3_capture_source = {
6756 .num_items = 2,
6757 .items = {
6758 { "Line", 0x2 },
6759 { "CD", 0x4 },
6760 },
6761};
6762
Takashi Iwai4953550a2009-06-30 15:28:30 +02006763static struct hda_input_mux alc883_3stack_6ch_intel = {
6764 .num_items = 4,
6765 .items = {
6766 { "Mic", 0x1 },
6767 { "Front Mic", 0x0 },
6768 { "Line", 0x2 },
6769 { "CD", 0x4 },
6770 },
6771};
6772
6773static struct hda_input_mux alc883_lenovo_101e_capture_source = {
6774 .num_items = 2,
6775 .items = {
6776 { "Mic", 0x1 },
6777 { "Line", 0x2 },
6778 },
6779};
6780
6781static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
6782 .num_items = 4,
6783 .items = {
6784 { "Mic", 0x0 },
6785 { "iMic", 0x1 },
6786 { "Line", 0x2 },
6787 { "CD", 0x4 },
6788 },
6789};
6790
6791static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
6792 .num_items = 2,
6793 .items = {
6794 { "Mic", 0x0 },
6795 { "Int Mic", 0x1 },
6796 },
6797};
6798
6799static struct hda_input_mux alc883_lenovo_sky_capture_source = {
6800 .num_items = 3,
6801 .items = {
6802 { "Mic", 0x0 },
6803 { "Front Mic", 0x1 },
6804 { "Line", 0x4 },
6805 },
6806};
6807
6808static struct hda_input_mux alc883_asus_eee1601_capture_source = {
6809 .num_items = 2,
6810 .items = {
6811 { "Mic", 0x0 },
6812 { "Line", 0x2 },
6813 },
6814};
6815
6816static struct hda_input_mux alc889A_mb31_capture_source = {
6817 .num_items = 2,
6818 .items = {
6819 { "Mic", 0x0 },
6820 /* Front Mic (0x01) unused */
6821 { "Line", 0x2 },
6822 /* Line 2 (0x03) unused */
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02006823 /* CD (0x04) unused? */
Takashi Iwai4953550a2009-06-30 15:28:30 +02006824 },
6825};
6826
6827/*
6828 * 2ch mode
6829 */
6830static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
6831 { 2, NULL }
6832};
6833
Kailang Yangdf694da2005-12-05 19:42:22 +01006834/*
Kailang Yang272a5272007-05-14 11:00:38 +02006835 * 2ch mode
6836 */
6837static struct hda_verb alc882_3ST_ch2_init[] = {
6838 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6839 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6840 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6841 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6842 { } /* end */
6843};
6844
6845/*
Takashi Iwai4953550a2009-06-30 15:28:30 +02006846 * 4ch mode
6847 */
6848static struct hda_verb alc882_3ST_ch4_init[] = {
6849 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6850 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6851 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6852 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6853 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6854 { } /* end */
6855};
6856
6857/*
Kailang Yang272a5272007-05-14 11:00:38 +02006858 * 6ch mode
6859 */
6860static struct hda_verb alc882_3ST_ch6_init[] = {
6861 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6862 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6863 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
6864 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6865 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6866 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6867 { } /* end */
6868};
6869
Takashi Iwai4953550a2009-06-30 15:28:30 +02006870static struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
Kailang Yang272a5272007-05-14 11:00:38 +02006871 { 2, alc882_3ST_ch2_init },
Takashi Iwai4953550a2009-06-30 15:28:30 +02006872 { 4, alc882_3ST_ch4_init },
Kailang Yang272a5272007-05-14 11:00:38 +02006873 { 6, alc882_3ST_ch6_init },
6874};
6875
Takashi Iwai4953550a2009-06-30 15:28:30 +02006876#define alc883_3ST_6ch_modes alc882_3ST_6ch_modes
6877
Kailang Yang272a5272007-05-14 11:00:38 +02006878/*
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04306879 * 2ch mode
6880 */
6881static struct hda_verb alc883_3ST_ch2_clevo_init[] = {
6882 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
6883 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6884 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6885 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6886 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6887 { } /* end */
6888};
6889
6890/*
6891 * 4ch mode
6892 */
6893static struct hda_verb alc883_3ST_ch4_clevo_init[] = {
6894 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6895 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6896 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6897 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6898 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6899 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6900 { } /* end */
6901};
6902
6903/*
6904 * 6ch mode
6905 */
6906static struct hda_verb alc883_3ST_ch6_clevo_init[] = {
6907 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6908 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6909 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6910 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
6911 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6912 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6913 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6914 { } /* end */
6915};
6916
6917static struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
6918 { 2, alc883_3ST_ch2_clevo_init },
6919 { 4, alc883_3ST_ch4_clevo_init },
6920 { 6, alc883_3ST_ch6_clevo_init },
6921};
6922
6923
6924/*
Kailang Yangdf694da2005-12-05 19:42:22 +01006925 * 6ch mode
6926 */
6927static struct hda_verb alc882_sixstack_ch6_init[] = {
6928 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
6929 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6930 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6931 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6932 { } /* end */
6933};
6934
6935/*
6936 * 8ch mode
6937 */
6938static struct hda_verb alc882_sixstack_ch8_init[] = {
6939 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6940 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6941 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6942 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6943 { } /* end */
6944};
6945
6946static struct hda_channel_mode alc882_sixstack_modes[2] = {
6947 { 6, alc882_sixstack_ch6_init },
6948 { 8, alc882_sixstack_ch8_init },
6949};
6950
Takashi Iwai87350ad2007-08-16 18:19:38 +02006951/*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04006952 * macbook pro ALC885 can switch LineIn to LineOut without losing Mic
Takashi Iwai87350ad2007-08-16 18:19:38 +02006953 */
6954
6955/*
6956 * 2ch mode
6957 */
6958static struct hda_verb alc885_mbp_ch2_init[] = {
6959 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6960 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6961 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6962 { } /* end */
6963};
6964
6965/*
Takashi Iwaia3f730a2009-08-31 08:15:26 +02006966 * 4ch mode
Takashi Iwai87350ad2007-08-16 18:19:38 +02006967 */
Takashi Iwaia3f730a2009-08-31 08:15:26 +02006968static struct hda_verb alc885_mbp_ch4_init[] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02006969 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6970 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6971 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6972 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6973 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6974 { } /* end */
6975};
6976
Takashi Iwaia3f730a2009-08-31 08:15:26 +02006977static struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02006978 { 2, alc885_mbp_ch2_init },
Takashi Iwaia3f730a2009-08-31 08:15:26 +02006979 { 4, alc885_mbp_ch4_init },
Takashi Iwai87350ad2007-08-16 18:19:38 +02006980};
6981
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02006982/*
6983 * 2ch
6984 * Speakers/Woofer/HP = Front
6985 * LineIn = Input
6986 */
6987static struct hda_verb alc885_mb5_ch2_init[] = {
6988 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6989 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6990 { } /* end */
6991};
6992
6993/*
6994 * 6ch mode
6995 * Speakers/HP = Front
6996 * Woofer = LFE
6997 * LineIn = Surround
6998 */
6999static struct hda_verb alc885_mb5_ch6_init[] = {
7000 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7001 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7002 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7003 { } /* end */
7004};
7005
7006static struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
7007 { 2, alc885_mb5_ch2_init },
7008 { 6, alc885_mb5_ch6_init },
7009};
Takashi Iwai87350ad2007-08-16 18:19:38 +02007010
Takashi Iwaid01aecd2010-02-23 08:07:15 +01007011#define alc885_macmini3_6ch_modes alc885_mb5_6ch_modes
Takashi Iwai4953550a2009-06-30 15:28:30 +02007012
7013/*
7014 * 2ch mode
7015 */
7016static struct hda_verb alc883_4ST_ch2_init[] = {
7017 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7018 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7019 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7020 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7021 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7022 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7023 { } /* end */
7024};
7025
7026/*
7027 * 4ch mode
7028 */
7029static struct hda_verb alc883_4ST_ch4_init[] = {
7030 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7031 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7032 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7033 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7034 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7035 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7036 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7037 { } /* end */
7038};
7039
7040/*
7041 * 6ch mode
7042 */
7043static struct hda_verb alc883_4ST_ch6_init[] = {
7044 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7045 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7046 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7047 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7048 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7049 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7050 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7051 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7052 { } /* end */
7053};
7054
7055/*
7056 * 8ch mode
7057 */
7058static struct hda_verb alc883_4ST_ch8_init[] = {
7059 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7060 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7061 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7062 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7063 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7064 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7065 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7066 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7067 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7068 { } /* end */
7069};
7070
7071static struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
7072 { 2, alc883_4ST_ch2_init },
7073 { 4, alc883_4ST_ch4_init },
7074 { 6, alc883_4ST_ch6_init },
7075 { 8, alc883_4ST_ch8_init },
7076};
7077
7078
7079/*
7080 * 2ch mode
7081 */
7082static struct hda_verb alc883_3ST_ch2_intel_init[] = {
7083 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7084 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7085 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7086 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7087 { } /* end */
7088};
7089
7090/*
7091 * 4ch mode
7092 */
7093static struct hda_verb alc883_3ST_ch4_intel_init[] = {
7094 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7095 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7096 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7097 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7098 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7099 { } /* end */
7100};
7101
7102/*
7103 * 6ch mode
7104 */
7105static struct hda_verb alc883_3ST_ch6_intel_init[] = {
7106 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7107 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7108 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
7109 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7110 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7111 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7112 { } /* end */
7113};
7114
7115static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
7116 { 2, alc883_3ST_ch2_intel_init },
7117 { 4, alc883_3ST_ch4_intel_init },
7118 { 6, alc883_3ST_ch6_intel_init },
7119};
7120
7121/*
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007122 * 2ch mode
7123 */
7124static struct hda_verb alc889_ch2_intel_init[] = {
7125 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7126 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 },
7127 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 },
7128 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00 },
7129 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7130 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7131 { } /* end */
7132};
7133
7134/*
Takashi Iwai4953550a2009-06-30 15:28:30 +02007135 * 6ch mode
7136 */
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007137static struct hda_verb alc889_ch6_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007138 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7139 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7140 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7141 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7142 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007143 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7144 { } /* end */
7145};
7146
7147/*
7148 * 8ch mode
7149 */
7150static struct hda_verb alc889_ch8_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007151 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7152 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7153 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7154 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7155 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x03 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007156 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7157 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007158 { } /* end */
7159};
7160
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007161static struct hda_channel_mode alc889_8ch_intel_modes[3] = {
7162 { 2, alc889_ch2_intel_init },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007163 { 6, alc889_ch6_intel_init },
7164 { 8, alc889_ch8_intel_init },
7165};
7166
7167/*
7168 * 6ch mode
7169 */
Takashi Iwai4953550a2009-06-30 15:28:30 +02007170static struct hda_verb alc883_sixstack_ch6_init[] = {
7171 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7172 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7173 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7174 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7175 { } /* end */
7176};
7177
7178/*
7179 * 8ch mode
7180 */
7181static struct hda_verb alc883_sixstack_ch8_init[] = {
7182 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7183 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7184 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7185 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7186 { } /* end */
7187};
7188
7189static struct hda_channel_mode alc883_sixstack_modes[2] = {
7190 { 6, alc883_sixstack_ch6_init },
7191 { 8, alc883_sixstack_ch8_init },
7192};
7193
7194
Linus Torvalds1da177e2005-04-16 15:20:36 -07007195/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
7196 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
7197 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01007198static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02007199 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007200 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007201 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007202 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007203 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7204 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007205 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7206 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007207 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007208 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007209 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7210 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7211 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7212 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7213 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7214 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007215 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007216 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7217 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007218 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007219 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007220 { } /* end */
7221};
7222
Takashi Iwai87350ad2007-08-16 18:19:38 +02007223static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007224 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7225 HDA_BIND_MUTE ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
7226 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7227 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT),
7228 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01007229 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7230 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02007231 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
7232 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01007233 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02007234 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
7235 { } /* end */
7236};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007237
7238static struct snd_kcontrol_new alc885_mb5_mixer[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007239 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7240 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
7241 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
7242 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
7243 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7244 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
Alex Murraya76221d2010-01-13 23:15:03 +10307245 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
7246 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007247 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7248 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7249 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
7250 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
7251 HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT),
7252 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0x00, HDA_INPUT),
7253 { } /* end */
7254};
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007255
Luke Yelaviche458b1f2010-02-12 16:28:29 +11007256static struct snd_kcontrol_new alc885_macmini3_mixer[] = {
7257 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7258 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
7259 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
7260 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
7261 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7262 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
7263 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
7264 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
7265 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
7266 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
7267 HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT),
7268 { } /* end */
7269};
7270
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08007271static struct snd_kcontrol_new alc885_imac91_mixer[] = {
7272 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7273 HDA_BIND_MUTE ("Line-Out Playback Switch", 0x0c, 0x02, HDA_INPUT),
7274 HDA_CODEC_MUTE ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT),
7275 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
7276 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7277 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7278 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
7279 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
7280 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
7281 { } /* end */
7282};
7283
7284
Kailang Yangbdd148a2007-05-08 15:19:08 +02007285static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
7286 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7287 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7288 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7289 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7290 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7291 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7292 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7293 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7294 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02007295 { } /* end */
7296};
7297
Kailang Yang272a5272007-05-14 11:00:38 +02007298static struct snd_kcontrol_new alc882_targa_mixer[] = {
7299 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7300 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7301 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7302 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7303 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7304 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7305 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7306 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7307 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02007308 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007309 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7310 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02007311 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007312 { } /* end */
7313};
7314
7315/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
7316 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
7317 */
7318static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
7319 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7320 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7321 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7322 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
7323 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7324 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7325 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7326 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7327 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
7328 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
7329 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7330 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02007331 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007332 { } /* end */
7333};
7334
Takashi Iwai914759b2007-09-06 14:52:04 +02007335static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
7336 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7337 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7338 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7339 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7340 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7341 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7342 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7343 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7344 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7345 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02007346 { } /* end */
7347};
7348
Kailang Yangdf694da2005-12-05 19:42:22 +01007349static struct snd_kcontrol_new alc882_chmode_mixer[] = {
7350 {
7351 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7352 .name = "Channel Mode",
7353 .info = alc_ch_mode_info,
7354 .get = alc_ch_mode_get,
7355 .put = alc_ch_mode_put,
7356 },
7357 { } /* end */
7358};
7359
Takashi Iwai4953550a2009-06-30 15:28:30 +02007360static struct hda_verb alc882_base_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007361 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007362 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7363 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007364 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02007365 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7366 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007367 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02007368 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7369 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007370 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02007371 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7372 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007373
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007374 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007375 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007376 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007377 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007378 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007379 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007380 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007381 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007382 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007383 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007384 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007385 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007386 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007387 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007388 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007389 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007390 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02007391 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007392 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7393 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02007394 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007395 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7396 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02007397 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007398 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7399 /* Line-2 In: Headphone output (output 0 - 0x0c) */
7400 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7401 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7402 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007403 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02007404 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007405
7406 /* FIXME: use matrix-type input source selection */
7407 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007408 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02007409 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007410 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02007411 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai05acb862005-06-10 19:50:25 +02007412 /* ADC2: mute amp left and right */
7413 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02007414 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02007415 /* ADC3: mute amp left and right */
7416 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02007417 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007418
7419 { }
7420};
7421
Takashi Iwai4953550a2009-06-30 15:28:30 +02007422static struct hda_verb alc882_adc1_init_verbs[] = {
7423 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
7424 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7425 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7426 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7427 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7428 /* ADC1: mute amp left and right */
7429 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7430 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
7431 { }
7432};
7433
Takashi Iwai4b146cb2006-07-28 14:42:36 +02007434static struct hda_verb alc882_eapd_verbs[] = {
7435 /* change to EAPD mode */
7436 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007437 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007438 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02007439};
7440
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007441static struct hda_verb alc889_eapd_verbs[] = {
7442 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
7443 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
7444 { }
7445};
7446
Wu Fengguang6732bd02009-07-30 09:19:14 +02007447static struct hda_verb alc_hp15_unsol_verbs[] = {
7448 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
7449 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7450 {}
7451};
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007452
7453static struct hda_verb alc885_init_verbs[] = {
7454 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Kailang Yang88102f32010-02-04 14:12:58 +01007455 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7456 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007457 /* Rear mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01007458 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7459 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007460 /* CLFE mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01007461 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7462 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007463 /* Side mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01007464 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7465 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007466
7467 /* Front HP Pin: output 0 (0x0c) */
Wu Fengguang6732bd02009-07-30 09:19:14 +02007468 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007469 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7470 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7471 /* Front Pin: output 0 (0x0c) */
7472 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7473 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7474 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7475 /* Rear Pin: output 1 (0x0d) */
7476 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7477 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7478 {0x19, AC_VERB_SET_CONNECT_SEL, 0x01},
7479 /* CLFE Pin: output 2 (0x0e) */
7480 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7481 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7482 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
7483 /* Side Pin: output 3 (0x0f) */
7484 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7485 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7486 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
7487 /* Mic (rear) pin: input vref at 80% */
7488 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7489 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7490 /* Front Mic pin: input vref at 80% */
7491 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7492 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7493 /* Line In pin: input */
7494 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7495 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7496
7497 /* Mixer elements: 0x18, , 0x1a, 0x1b */
7498 /* Input mixer1 */
Kailang Yang88102f32010-02-04 14:12:58 +01007499 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007500 /* Input mixer2 */
7501 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007502 /* Input mixer3 */
Kailang Yang88102f32010-02-04 14:12:58 +01007503 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007504 /* ADC2: mute amp left and right */
7505 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7506 /* ADC3: mute amp left and right */
7507 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7508
7509 { }
7510};
7511
7512static struct hda_verb alc885_init_input_verbs[] = {
7513 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7514 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
7515 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
7516 { }
7517};
7518
7519
7520/* Unmute Selector 24h and set the default input to front mic */
7521static struct hda_verb alc889_init_input_verbs[] = {
7522 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
7523 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7524 { }
7525};
7526
7527
Takashi Iwai4953550a2009-06-30 15:28:30 +02007528#define alc883_init_verbs alc882_base_init_verbs
7529
Tobin Davis9102cd12006-12-15 10:02:12 +01007530/* Mac Pro test */
7531static struct snd_kcontrol_new alc882_macpro_mixer[] = {
7532 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7533 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7534 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
7535 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
7536 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007537 /* FIXME: this looks suspicious...
Jaroslav Kyselad355c82a2009-11-03 15:47:25 +01007538 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT),
7539 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007540 */
Tobin Davis9102cd12006-12-15 10:02:12 +01007541 { } /* end */
7542};
7543
7544static struct hda_verb alc882_macpro_init_verbs[] = {
7545 /* Front mixer: unmute input/output amp left and right (volume = 0) */
7546 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7547 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7548 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7549 /* Front Pin: output 0 (0x0c) */
7550 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7551 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7552 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7553 /* Front Mic pin: input vref at 80% */
7554 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7555 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7556 /* Speaker: output */
7557 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7558 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7559 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
7560 /* Headphone output (output 0 - 0x0c) */
7561 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7562 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7563 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
7564
7565 /* FIXME: use matrix-type input source selection */
7566 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7567 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
7568 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7569 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7570 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7571 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7572 /* Input mixer2 */
7573 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7574 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7575 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7576 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7577 /* Input mixer3 */
7578 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7579 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7580 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7581 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7582 /* ADC1: mute amp left and right */
7583 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7584 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
7585 /* ADC2: mute amp left and right */
7586 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7587 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7588 /* ADC3: mute amp left and right */
7589 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7590 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7591
7592 { }
7593};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007594
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007595/* Macbook 5,1 */
7596static struct hda_verb alc885_mb5_init_verbs[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007597 /* DACs */
7598 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7599 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7600 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7601 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007602 /* Front mixer */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007603 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7604 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7605 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007606 /* Surround mixer */
7607 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7608 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7609 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7610 /* LFE mixer */
7611 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7612 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7613 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7614 /* HP mixer */
7615 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7616 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7617 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7618 /* Front Pin (0x0c) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007619 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
7620 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007621 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
7622 /* LFE Pin (0x0e) */
7623 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
7624 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7625 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
7626 /* HP Pin (0x0f) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007627 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7628 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007629 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
Alex Murraya76221d2010-01-13 23:15:03 +10307630 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007631 /* Front Mic pin: input vref at 80% */
7632 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7633 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7634 /* Line In pin */
7635 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7636 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7637
7638 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7639 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7640 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7641 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7642 { }
7643};
7644
Luke Yelaviche458b1f2010-02-12 16:28:29 +11007645/* Macmini 3,1 */
7646static struct hda_verb alc885_macmini3_init_verbs[] = {
7647 /* DACs */
7648 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7649 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7650 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7651 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7652 /* Front mixer */
7653 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7654 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7655 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7656 /* Surround mixer */
7657 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7658 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7659 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7660 /* LFE mixer */
7661 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7662 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7663 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7664 /* HP mixer */
7665 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7666 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7667 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7668 /* Front Pin (0x0c) */
7669 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
7670 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7671 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
7672 /* LFE Pin (0x0e) */
7673 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
7674 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7675 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
7676 /* HP Pin (0x0f) */
7677 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7678 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7679 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
7680 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7681 /* Line In pin */
7682 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7683 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7684
7685 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7686 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7687 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7688 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7689 { }
7690};
7691
Takashi Iwai87350ad2007-08-16 18:19:38 +02007692/* Macbook Pro rev3 */
7693static struct hda_verb alc885_mbp3_init_verbs[] = {
7694 /* Front mixer: unmute input/output amp left and right (volume = 0) */
7695 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7696 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7697 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7698 /* Rear mixer */
7699 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7700 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7701 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007702 /* HP mixer */
7703 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7704 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7705 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai87350ad2007-08-16 18:19:38 +02007706 /* Front Pin: output 0 (0x0c) */
7707 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7708 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7709 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007710 /* HP Pin: output 0 (0x0e) */
Takashi Iwai87350ad2007-08-16 18:19:38 +02007711 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007712 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7713 {0x15, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai87350ad2007-08-16 18:19:38 +02007714 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7715 /* Mic (rear) pin: input vref at 80% */
7716 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7717 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7718 /* Front Mic pin: input vref at 80% */
7719 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7720 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7721 /* Line In pin: use output 1 when in LineOut mode */
7722 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7723 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7724 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
7725
7726 /* FIXME: use matrix-type input source selection */
7727 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7728 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
7729 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7730 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7731 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7732 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7733 /* Input mixer2 */
7734 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7735 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7736 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7737 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7738 /* Input mixer3 */
7739 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7740 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7741 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7742 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7743 /* ADC1: mute amp left and right */
7744 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7745 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
7746 /* ADC2: mute amp left and right */
7747 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7748 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7749 /* ADC3: mute amp left and right */
7750 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7751 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7752
7753 { }
7754};
7755
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08007756/* iMac 9,1 */
7757static struct hda_verb alc885_imac91_init_verbs[] = {
7758 /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */
7759 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7760 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7761 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7762 /* Rear mixer */
7763 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7764 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7765 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7766 /* HP Pin: output 0 (0x0c) */
7767 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7768 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7769 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7770 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7771 /* Internal Speakers: output 0 (0x0d) */
7772 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7773 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7774 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7775 /* Mic (rear) pin: input vref at 80% */
7776 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7777 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7778 /* Front Mic pin: input vref at 80% */
7779 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7780 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7781 /* Line In pin: use output 1 when in LineOut mode */
7782 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7783 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7784 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
7785
7786 /* FIXME: use matrix-type input source selection */
7787 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7788 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
7789 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7790 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7791 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7792 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7793 /* Input mixer2 */
7794 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7795 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7796 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7797 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7798 /* Input mixer3 */
7799 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7800 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7801 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7802 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7803 /* ADC1: mute amp left and right */
7804 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7805 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
7806 /* ADC2: mute amp left and right */
7807 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7808 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7809 /* ADC3: mute amp left and right */
7810 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7811 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7812
7813 { }
7814};
7815
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007816/* iMac 24 mixer. */
7817static struct snd_kcontrol_new alc885_imac24_mixer[] = {
7818 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7819 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
7820 { } /* end */
7821};
7822
7823/* iMac 24 init verbs. */
7824static struct hda_verb alc885_imac24_init_verbs[] = {
7825 /* Internal speakers: output 0 (0x0c) */
7826 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7827 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7828 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
7829 /* Internal speakers: output 0 (0x0c) */
7830 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7831 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7832 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
7833 /* Headphone: output 0 (0x0c) */
7834 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7835 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7836 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7837 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7838 /* Front Mic: input vref at 80% */
7839 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7840 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7841 { }
7842};
7843
7844/* Toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02007845static void alc885_imac24_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007846{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007847 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007848
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007849 spec->autocfg.hp_pins[0] = 0x14;
7850 spec->autocfg.speaker_pins[0] = 0x18;
7851 spec->autocfg.speaker_pins[1] = 0x1a;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007852}
7853
Takashi Iwai9d54f082010-02-22 08:34:40 +01007854#define alc885_mb5_setup alc885_imac24_setup
7855#define alc885_macmini3_setup alc885_imac24_setup
7856
Takashi Iwai4f5d17062009-08-11 18:17:46 +02007857static void alc885_mbp3_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007858{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007859 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007860
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007861 spec->autocfg.hp_pins[0] = 0x15;
7862 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai87350ad2007-08-16 18:19:38 +02007863}
7864
Takashi Iwai9d54f082010-02-22 08:34:40 +01007865static void alc885_imac91_setup(struct hda_codec *codec)
Alex Murraya76221d2010-01-13 23:15:03 +10307866{
Takashi Iwai9d54f082010-02-22 08:34:40 +01007867 struct alc_spec *spec = codec->spec;
Alex Murraya76221d2010-01-13 23:15:03 +10307868
Takashi Iwai9d54f082010-02-22 08:34:40 +01007869 spec->autocfg.hp_pins[0] = 0x14;
7870 spec->autocfg.speaker_pins[0] = 0x15;
7871 spec->autocfg.speaker_pins[1] = 0x1a;
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08007872}
Takashi Iwai87350ad2007-08-16 18:19:38 +02007873
Kailang Yang272a5272007-05-14 11:00:38 +02007874static struct hda_verb alc882_targa_verbs[] = {
7875 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7876 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7877
7878 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7879 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02007880
Kailang Yang272a5272007-05-14 11:00:38 +02007881 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
7882 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
7883 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
7884
7885 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yang272a5272007-05-14 11:00:38 +02007886 { } /* end */
7887};
7888
7889/* toggle speaker-output according to the hp-jack state */
7890static void alc882_targa_automute(struct hda_codec *codec)
7891{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007892 struct alc_spec *spec = codec->spec;
7893 alc_automute_amp(codec);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02007894 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007895 spec->jack_present ? 1 : 3);
7896}
7897
Takashi Iwai4f5d17062009-08-11 18:17:46 +02007898static void alc882_targa_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007899{
7900 struct alc_spec *spec = codec->spec;
7901
7902 spec->autocfg.hp_pins[0] = 0x14;
7903 spec->autocfg.speaker_pins[0] = 0x1b;
Kailang Yang272a5272007-05-14 11:00:38 +02007904}
7905
7906static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
7907{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007908 if ((res >> 26) == ALC880_HP_EVENT)
Kailang Yang272a5272007-05-14 11:00:38 +02007909 alc882_targa_automute(codec);
Kailang Yang272a5272007-05-14 11:00:38 +02007910}
7911
7912static struct hda_verb alc882_asus_a7j_verbs[] = {
7913 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7914 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7915
7916 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7917 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7918 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02007919
Kailang Yang272a5272007-05-14 11:00:38 +02007920 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
7921 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
7922 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
7923
7924 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
7925 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
7926 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
7927 { } /* end */
7928};
7929
Takashi Iwai914759b2007-09-06 14:52:04 +02007930static struct hda_verb alc882_asus_a7m_verbs[] = {
7931 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7932 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7933
7934 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7935 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7936 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02007937
Takashi Iwai914759b2007-09-06 14:52:04 +02007938 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
7939 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
7940 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
7941
7942 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
7943 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
7944 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
7945 { } /* end */
7946};
7947
Tobin Davis9102cd12006-12-15 10:02:12 +01007948static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
7949{
7950 unsigned int gpiostate, gpiomask, gpiodir;
7951
7952 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
7953 AC_VERB_GET_GPIO_DATA, 0);
7954
7955 if (!muted)
7956 gpiostate |= (1 << pin);
7957 else
7958 gpiostate &= ~(1 << pin);
7959
7960 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
7961 AC_VERB_GET_GPIO_MASK, 0);
7962 gpiomask |= (1 << pin);
7963
7964 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
7965 AC_VERB_GET_GPIO_DIRECTION, 0);
7966 gpiodir |= (1 << pin);
7967
7968
7969 snd_hda_codec_write(codec, codec->afg, 0,
7970 AC_VERB_SET_GPIO_MASK, gpiomask);
7971 snd_hda_codec_write(codec, codec->afg, 0,
7972 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
7973
7974 msleep(1);
7975
7976 snd_hda_codec_write(codec, codec->afg, 0,
7977 AC_VERB_SET_GPIO_DATA, gpiostate);
7978}
7979
Takashi Iwai7debbe52007-08-16 15:01:03 +02007980/* set up GPIO at initialization */
7981static void alc885_macpro_init_hook(struct hda_codec *codec)
7982{
7983 alc882_gpio_mute(codec, 0, 0);
7984 alc882_gpio_mute(codec, 1, 0);
7985}
7986
7987/* set up GPIO and update auto-muting at initialization */
7988static void alc885_imac24_init_hook(struct hda_codec *codec)
7989{
7990 alc885_macpro_init_hook(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +02007991 alc_automute_amp(codec);
Takashi Iwai7debbe52007-08-16 15:01:03 +02007992}
7993
Kailang Yangdf694da2005-12-05 19:42:22 +01007994/*
7995 * generic initialization of ADC, input mixers and output mixers
7996 */
Takashi Iwai4953550a2009-06-30 15:28:30 +02007997static struct hda_verb alc883_auto_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01007998 /*
7999 * Unmute ADC0-2 and set the default input to mic-in
8000 */
Kailang Yangdf694da2005-12-05 19:42:22 +01008001 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8002 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8003 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8004 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8005
Kailang Yangdf694da2005-12-05 19:42:22 +01008006 /*
8007 * Set up output mixers (0x0c - 0x0f)
8008 */
8009 /* set vol=0 to output mixers */
8010 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8011 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8012 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8013 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8014 /* set up input amps for analog loopback */
8015 /* Amp Indices: DAC = 0, mixer = 1 */
8016 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8017 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8018 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8019 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8020 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8021 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8022 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8023 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8024 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8025 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8026
8027 /* FIXME: use matrix-type input source selection */
8028 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Kailang Yangdf694da2005-12-05 19:42:22 +01008029 /* Input mixer2 */
Kailang Yang88102f32010-02-04 14:12:58 +01008030 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008031 /* Input mixer3 */
Kailang Yang88102f32010-02-04 14:12:58 +01008032 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008033 { }
8034};
8035
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008036/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
8037static struct hda_verb alc889A_mb31_ch2_init[] = {
8038 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
8039 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8040 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
8041 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
8042 { } /* end */
8043};
8044
8045/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */
8046static struct hda_verb alc889A_mb31_ch4_init[] = {
8047 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
8048 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8049 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
8050 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
8051 { } /* end */
8052};
8053
8054/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */
8055static struct hda_verb alc889A_mb31_ch5_init[] = {
8056 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */
8057 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8058 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
8059 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
8060 { } /* end */
8061};
8062
8063/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */
8064static struct hda_verb alc889A_mb31_ch6_init[] = {
8065 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */
8066 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */
8067 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
8068 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
8069 { } /* end */
8070};
8071
8072static struct hda_channel_mode alc889A_mb31_6ch_modes[4] = {
8073 { 2, alc889A_mb31_ch2_init },
8074 { 4, alc889A_mb31_ch4_init },
8075 { 5, alc889A_mb31_ch5_init },
8076 { 6, alc889A_mb31_ch6_init },
8077};
8078
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008079static struct hda_verb alc883_medion_eapd_verbs[] = {
8080 /* eanable EAPD on medion laptop */
8081 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8082 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
8083 { }
8084};
8085
Takashi Iwai4953550a2009-06-30 15:28:30 +02008086#define alc883_base_mixer alc882_base_mixer
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008087
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008088static struct snd_kcontrol_new alc883_mitac_mixer[] = {
8089 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8090 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8091 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8092 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8093 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8094 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8095 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8096 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8097 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8098 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8099 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8100 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
8101 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008102 { } /* end */
8103};
8104
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008105static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01008106 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8107 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8108 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8109 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8110 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8111 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8112 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8113 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8114 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8115 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01008116 { } /* end */
8117};
8118
Jiang zhefb97dc62008-03-06 11:07:11 +01008119static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
8120 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8121 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8122 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8123 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8124 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8125 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8126 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8127 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8128 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8129 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01008130 { } /* end */
8131};
8132
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008133static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
8134 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8135 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8136 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8137 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8138 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8139 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8140 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8141 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008142 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008143 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8144 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008145 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008146 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008147 { } /* end */
8148};
8149
8150static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
8151 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8152 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8153 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8154 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8155 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8156 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8157 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8158 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8159 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8160 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8161 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8162 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8163 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8164 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008165 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008166 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8167 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008168 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008169 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008170 { } /* end */
8171};
8172
Jiang zhe17bba1b2008-06-04 12:11:07 +02008173static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
8174 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8175 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8176 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8177 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8178 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
8179 HDA_OUTPUT),
8180 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8181 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8182 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8183 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8184 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8185 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8186 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8187 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8188 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8189 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
8190 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8191 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8192 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
8193 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008194 { } /* end */
8195};
8196
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008197static struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
8198 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8199 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8200 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8201 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8202 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
8203 HDA_OUTPUT),
8204 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8205 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8206 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8207 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8208 HDA_BIND_MUTE("Speaker Playback Switch", 0x0f, 2, HDA_INPUT),
8209 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8210 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8211 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8212 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
8213 HDA_CODEC_VOLUME("Mic Boost", 0x1b, 0, HDA_INPUT),
8214 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
8215 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8216 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
8217 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8218 { } /* end */
8219};
8220
Takashi Iwaid1d985f2006-11-23 19:27:12 +01008221static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02008222 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008223 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008224 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008225 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008226 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8227 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008228 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8229 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008230 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8231 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8232 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8233 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8234 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8235 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008236 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008237 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8238 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008239 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008240 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008241 { } /* end */
8242};
8243
Sasha Alexandrc2592492009-06-16 14:52:54 -04008244static struct snd_kcontrol_new alc883_targa_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02008245 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008246 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008247 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008248 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008249 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8250 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8251 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8252 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8253 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8254 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8255 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8256 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8257 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8258 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8259 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008260 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008261 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008262 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008263};
Kailang Yangccc656c2006-10-17 12:32:26 +02008264
Sasha Alexandrc2592492009-06-16 14:52:54 -04008265static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02008266 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008267 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008268 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008269 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008270 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8271 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8272 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008273 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008274 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe4383fae2008-04-14 12:58:57 +02008275 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8276 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8277 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008278 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008279};
Kailang Yangccc656c2006-10-17 12:32:26 +02008280
Takashi Iwaib99dba32009-09-17 18:23:00 +02008281static struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
8282 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8283 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
8284 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8285 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8286 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8287 { } /* end */
8288};
8289
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008290static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
8291 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8292 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01008293 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8294 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008295 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8296 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8297 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8298 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008299 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008300};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008301
Kailang Yang272a5272007-05-14 11:00:38 +02008302static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
8303 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8304 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
8305 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8306 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8307 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8308 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8309 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8310 HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8311 HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008312 { } /* end */
8313};
8314
8315static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
8316 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8317 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8318 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8319 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8320 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8321 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8322 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8323 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8324 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008325 { } /* end */
Kailang Yangea1fb292008-08-26 12:58:38 +02008326};
Kailang Yang272a5272007-05-14 11:00:38 +02008327
Tobin Davis2880a8672007-08-07 11:50:26 +02008328static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02008329 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8330 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a8672007-08-07 11:50:26 +02008331 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a8672007-08-07 11:50:26 +02008332 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8333 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02008334 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8335 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8336 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a8672007-08-07 11:50:26 +02008337 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02008338};
Tobin Davis2880a8672007-08-07 11:50:26 +02008339
Tony Vroond2fd4b02009-06-21 00:40:10 +01008340static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
8341 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8342 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8343 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8344 HDA_BIND_MUTE("LFE Playback Switch", 0x0f, 2, HDA_INPUT),
Tony Vroon684a8842009-06-26 09:27:50 +01008345 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8346 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01008347 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8348 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8349 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8350 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8351 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8352 { } /* end */
8353};
8354
Kailang Yange2757d52008-08-26 13:17:46 +02008355static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
8356 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8357 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8358 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
8359 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
8360 HDA_CODEC_VOLUME_MONO("Center Playback Volume",
8361 0x0d, 1, 0x0, HDA_OUTPUT),
8362 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
8363 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
8364 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
8365 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8366 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02008367 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8368 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8369 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8370 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8371 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8372 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8373 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8374 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8375 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
8376 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02008377 { } /* end */
8378};
8379
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008380static struct snd_kcontrol_new alc889A_mb31_mixer[] = {
8381 /* Output mixers */
8382 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8383 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
8384 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
8385 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
8386 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00,
8387 HDA_OUTPUT),
8388 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT),
8389 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT),
8390 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT),
8391 /* Output switches */
8392 HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT),
8393 HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT),
8394 HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT),
8395 /* Boost mixers */
8396 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
8397 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
8398 /* Input mixers */
8399 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
8400 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
8401 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8402 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8403 { } /* end */
8404};
8405
Guido Günther3e1647c2009-06-05 00:47:26 +02008406static struct snd_kcontrol_new alc883_vaiott_mixer[] = {
8407 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8408 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8409 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8410 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8411 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
8412 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8413 { } /* end */
8414};
8415
Kailang Yange2757d52008-08-26 13:17:46 +02008416static struct hda_bind_ctls alc883_bind_cap_vol = {
8417 .ops = &snd_hda_bind_vol,
8418 .values = {
8419 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
8420 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
8421 0
8422 },
8423};
8424
8425static struct hda_bind_ctls alc883_bind_cap_switch = {
8426 .ops = &snd_hda_bind_sw,
8427 .values = {
8428 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
8429 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
8430 0
8431 },
8432};
8433
8434static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
8435 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8436 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8437 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8438 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8439 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8440 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8441 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8442 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008443 { } /* end */
8444};
8445
8446static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02008447 HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
8448 HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
8449 {
8450 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8451 /* .name = "Capture Source", */
8452 .name = "Input Source",
8453 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01008454 .info = alc_mux_enum_info,
8455 .get = alc_mux_enum_get,
8456 .put = alc_mux_enum_put,
Kailang Yange2757d52008-08-26 13:17:46 +02008457 },
8458 { } /* end */
8459};
8460
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008461static struct snd_kcontrol_new alc883_chmode_mixer[] = {
8462 {
8463 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8464 .name = "Channel Mode",
8465 .info = alc_ch_mode_info,
8466 .get = alc_ch_mode_get,
8467 .put = alc_ch_mode_put,
8468 },
8469 { } /* end */
8470};
8471
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008472/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008473static void alc883_mitac_setup(struct hda_codec *codec)
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008474{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008475 struct alc_spec *spec = codec->spec;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008476
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008477 spec->autocfg.hp_pins[0] = 0x15;
8478 spec->autocfg.speaker_pins[0] = 0x14;
8479 spec->autocfg.speaker_pins[1] = 0x17;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008480}
8481
8482/* auto-toggle front mic */
8483/*
8484static void alc883_mitac_mic_automute(struct hda_codec *codec)
8485{
Wu Fengguang864f92b2009-11-18 12:38:02 +08008486 unsigned char bits = snd_hda_jack_detect(codec, 0x18) ? HDA_AMP_MUTE : 0;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008487
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008488 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
8489}
8490*/
8491
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008492static struct hda_verb alc883_mitac_verbs[] = {
8493 /* HP */
8494 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8495 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8496 /* Subwoofer */
8497 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
8498 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8499
8500 /* enable unsolicited event */
8501 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8502 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
8503
8504 { } /* end */
8505};
8506
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04308507static struct hda_verb alc883_clevo_m540r_verbs[] = {
8508 /* HP */
8509 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8510 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8511 /* Int speaker */
8512 /*{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},*/
8513
8514 /* enable unsolicited event */
8515 /*
8516 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8517 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
8518 */
8519
8520 { } /* end */
8521};
8522
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008523static struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01008524 /* HP */
8525 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8526 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8527 /* Int speaker */
8528 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
8529 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8530
8531 /* enable unsolicited event */
8532 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008533 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01008534
8535 { } /* end */
8536};
8537
Jiang zhefb97dc62008-03-06 11:07:11 +01008538static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
8539 /* HP */
8540 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8541 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8542 /* Subwoofer */
8543 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
8544 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8545
8546 /* enable unsolicited event */
8547 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8548
8549 { } /* end */
8550};
8551
Sasha Alexandrc2592492009-06-16 14:52:54 -04008552static struct hda_verb alc883_targa_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02008553 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8554 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8555
8556 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8557 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008558
David Heidelberger64a8be72009-06-08 16:15:18 +02008559/* Connect Line-Out side jack (SPDIF) to Side */
8560 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8561 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8562 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
8563/* Connect Mic jack to CLFE */
8564 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8565 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8566 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
8567/* Connect Line-in jack to Surround */
8568 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8569 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8570 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
8571/* Connect HP out jack to Front */
8572 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8573 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8574 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangccc656c2006-10-17 12:32:26 +02008575
8576 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangccc656c2006-10-17 12:32:26 +02008577
8578 { } /* end */
8579};
8580
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008581static struct hda_verb alc883_lenovo_101e_verbs[] = {
8582 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8583 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
8584 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
8585 { } /* end */
8586};
8587
Kailang Yang272a5272007-05-14 11:00:38 +02008588static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
8589 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8590 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8591 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8592 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8593 { } /* end */
8594};
8595
8596static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
8597 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8598 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8599 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8600 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
8601 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8602 { } /* end */
8603};
8604
Kailang Yang189609a2007-08-20 11:31:23 +02008605static struct hda_verb alc883_haier_w66_verbs[] = {
8606 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8607 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8608
8609 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8610
8611 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8612 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8613 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8614 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8615 { } /* end */
8616};
8617
Kailang Yange2757d52008-08-26 13:17:46 +02008618static struct hda_verb alc888_lenovo_sky_verbs[] = {
8619 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8620 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8621 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8622 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8623 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8624 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8625 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8626 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8627 { } /* end */
8628};
8629
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008630static struct hda_verb alc888_6st_dell_verbs[] = {
8631 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8632 { }
8633};
8634
Guido Günther3e1647c2009-06-05 00:47:26 +02008635static struct hda_verb alc883_vaiott_verbs[] = {
8636 /* HP */
8637 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8638 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8639
8640 /* enable unsolicited event */
8641 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8642
8643 { } /* end */
8644};
8645
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008646static void alc888_3st_hp_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008647{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008648 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008649
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008650 spec->autocfg.hp_pins[0] = 0x1b;
8651 spec->autocfg.speaker_pins[0] = 0x14;
8652 spec->autocfg.speaker_pins[1] = 0x16;
8653 spec->autocfg.speaker_pins[2] = 0x18;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008654}
8655
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008656static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008657 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01008658 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
8659 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008660 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008661 { } /* end */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008662};
8663
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008664/*
8665 * 2ch mode
8666 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008667static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008668 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
8669 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8670 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
8671 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008672 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008673};
8674
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008675/*
8676 * 4ch mode
8677 */
8678static struct hda_verb alc888_3st_hp_4ch_init[] = {
8679 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
8680 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8681 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8682 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8683 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
8684 { } /* end */
8685};
8686
8687/*
8688 * 6ch mode
8689 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008690static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008691 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8692 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008693 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008694 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8695 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008696 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
8697 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008698};
8699
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008700static struct hda_channel_mode alc888_3st_hp_modes[3] = {
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008701 { 2, alc888_3st_hp_2ch_init },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008702 { 4, alc888_3st_hp_4ch_init },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008703 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008704};
8705
Kailang Yang272a5272007-05-14 11:00:38 +02008706/* toggle front-jack and RCA according to the hp-jack state */
8707static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
8708{
Wu Fengguang864f92b2009-11-18 12:38:02 +08008709 unsigned int present = snd_hda_jack_detect(codec, 0x1b);
Kailang Yangea1fb292008-08-26 12:58:38 +02008710
Takashi Iwai47fd8302007-08-10 17:11:07 +02008711 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8712 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8713 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8714 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02008715}
8716
8717/* toggle RCA according to the front-jack state */
8718static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
8719{
Wu Fengguang864f92b2009-11-18 12:38:02 +08008720 unsigned int present = snd_hda_jack_detect(codec, 0x14);
Kailang Yangea1fb292008-08-26 12:58:38 +02008721
Takashi Iwai47fd8302007-08-10 17:11:07 +02008722 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8723 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02008724}
Takashi Iwai47fd8302007-08-10 17:11:07 +02008725
Kailang Yang272a5272007-05-14 11:00:38 +02008726static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
8727 unsigned int res)
8728{
8729 if ((res >> 26) == ALC880_HP_EVENT)
8730 alc888_lenovo_ms7195_front_automute(codec);
8731 if ((res >> 26) == ALC880_FRONT_EVENT)
8732 alc888_lenovo_ms7195_rca_automute(codec);
8733}
8734
8735static struct hda_verb alc883_medion_md2_verbs[] = {
8736 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8737 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8738
8739 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8740
8741 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8742 { } /* end */
8743};
8744
8745/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008746static void alc883_medion_md2_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +02008747{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008748 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02008749
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008750 spec->autocfg.hp_pins[0] = 0x14;
8751 spec->autocfg.speaker_pins[0] = 0x15;
Kailang Yang272a5272007-05-14 11:00:38 +02008752}
8753
Kailang Yangccc656c2006-10-17 12:32:26 +02008754/* toggle speaker-output according to the hp-jack state */
Sasha Alexandrc2592492009-06-16 14:52:54 -04008755#define alc883_targa_init_hook alc882_targa_init_hook
8756#define alc883_targa_unsol_event alc882_targa_unsol_event
Jiang zhe368c7a92008-03-04 11:20:33 +01008757
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008758static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
8759{
8760 unsigned int present;
8761
Takashi Iwaid56757a2009-11-18 08:00:14 +01008762 present = snd_hda_jack_detect(codec, 0x18);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008763 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
8764 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8765}
8766
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008767static void alc883_clevo_m720_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008768{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008769 struct alc_spec *spec = codec->spec;
8770
8771 spec->autocfg.hp_pins[0] = 0x15;
8772 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008773}
8774
8775static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
8776{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008777 alc_automute_amp(codec);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008778 alc883_clevo_m720_mic_automute(codec);
8779}
8780
8781static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01008782 unsigned int res)
8783{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008784 switch (res >> 26) {
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008785 case ALC880_MIC_EVENT:
8786 alc883_clevo_m720_mic_automute(codec);
8787 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008788 default:
8789 alc_automute_amp_unsol_event(codec, res);
8790 break;
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008791 }
Jiang zhe368c7a92008-03-04 11:20:33 +01008792}
8793
Jiang zhefb97dc62008-03-06 11:07:11 +01008794/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008795static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01008796{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008797 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01008798
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008799 spec->autocfg.hp_pins[0] = 0x14;
8800 spec->autocfg.speaker_pins[0] = 0x15;
Jiang zhefb97dc62008-03-06 11:07:11 +01008801}
8802
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008803static void alc883_haier_w66_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01008804{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008805 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01008806
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008807 spec->autocfg.hp_pins[0] = 0x1b;
8808 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang189609a2007-08-20 11:31:23 +02008809}
8810
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008811static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
8812{
Wu Fengguang864f92b2009-11-18 12:38:02 +08008813 int bits = snd_hda_jack_detect(codec, 0x14) ? HDA_AMP_MUTE : 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008814
Takashi Iwai47fd8302007-08-10 17:11:07 +02008815 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8816 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008817}
8818
8819static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
8820{
Wu Fengguang864f92b2009-11-18 12:38:02 +08008821 int bits = snd_hda_jack_detect(codec, 0x1b) ? HDA_AMP_MUTE : 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008822
Takashi Iwai47fd8302007-08-10 17:11:07 +02008823 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8824 HDA_AMP_MUTE, bits);
8825 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8826 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008827}
8828
8829static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
8830 unsigned int res)
8831{
8832 if ((res >> 26) == ALC880_HP_EVENT)
8833 alc883_lenovo_101e_all_automute(codec);
8834 if ((res >> 26) == ALC880_FRONT_EVENT)
8835 alc883_lenovo_101e_ispeaker_automute(codec);
8836}
8837
Takashi Iwai676a9b52007-08-16 15:23:35 +02008838/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008839static void alc883_acer_aspire_setup(struct hda_codec *codec)
Takashi Iwai676a9b52007-08-16 15:23:35 +02008840{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008841 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02008842
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008843 spec->autocfg.hp_pins[0] = 0x14;
8844 spec->autocfg.speaker_pins[0] = 0x15;
8845 spec->autocfg.speaker_pins[1] = 0x16;
Takashi Iwai676a9b52007-08-16 15:23:35 +02008846}
8847
Kailang Yangd1a991a2007-08-15 16:21:59 +02008848static struct hda_verb alc883_acer_eapd_verbs[] = {
8849 /* HP Pin: output 0 (0x0c) */
8850 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8851 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8852 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8853 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02008854 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8855 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02008856 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02008857 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
8858 /* eanable EAPD on medion laptop */
8859 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8860 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02008861 /* enable unsolicited event */
8862 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02008863 { }
8864};
8865
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02008866static struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
8867 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8868 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
8869 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8870 { } /* end */
8871};
8872
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008873static void alc888_6st_dell_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008874{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008875 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02008876
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008877 spec->autocfg.hp_pins[0] = 0x1b;
8878 spec->autocfg.speaker_pins[0] = 0x14;
8879 spec->autocfg.speaker_pins[1] = 0x15;
8880 spec->autocfg.speaker_pins[2] = 0x16;
8881 spec->autocfg.speaker_pins[3] = 0x17;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008882}
8883
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008884static void alc888_lenovo_sky_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008885{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008886 struct alc_spec *spec = codec->spec;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008887
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008888 spec->autocfg.hp_pins[0] = 0x1b;
8889 spec->autocfg.speaker_pins[0] = 0x14;
8890 spec->autocfg.speaker_pins[1] = 0x15;
8891 spec->autocfg.speaker_pins[2] = 0x16;
8892 spec->autocfg.speaker_pins[3] = 0x17;
8893 spec->autocfg.speaker_pins[4] = 0x1a;
Kailang Yange2757d52008-08-26 13:17:46 +02008894}
8895
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008896static void alc883_vaiott_setup(struct hda_codec *codec)
Guido Günther3e1647c2009-06-05 00:47:26 +02008897{
8898 struct alc_spec *spec = codec->spec;
8899
8900 spec->autocfg.hp_pins[0] = 0x15;
8901 spec->autocfg.speaker_pins[0] = 0x14;
8902 spec->autocfg.speaker_pins[1] = 0x17;
Guido Günther3e1647c2009-06-05 00:47:26 +02008903}
8904
Kailang Yange2757d52008-08-26 13:17:46 +02008905static struct hda_verb alc888_asus_m90v_verbs[] = {
8906 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8907 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8908 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8909 /* enable unsolicited event */
8910 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8911 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
8912 { } /* end */
8913};
8914
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008915static void alc883_mode2_setup(struct hda_codec *codec)
Kailang Yange2757d52008-08-26 13:17:46 +02008916{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008917 struct alc_spec *spec = codec->spec;
Kailang Yange2757d52008-08-26 13:17:46 +02008918
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008919 spec->autocfg.hp_pins[0] = 0x1b;
8920 spec->autocfg.speaker_pins[0] = 0x14;
8921 spec->autocfg.speaker_pins[1] = 0x15;
8922 spec->autocfg.speaker_pins[2] = 0x16;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008923 spec->ext_mic.pin = 0x18;
8924 spec->int_mic.pin = 0x19;
8925 spec->ext_mic.mux_idx = 0;
8926 spec->int_mic.mux_idx = 1;
8927 spec->auto_mic = 1;
Kailang Yange2757d52008-08-26 13:17:46 +02008928}
8929
8930static struct hda_verb alc888_asus_eee1601_verbs[] = {
8931 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8932 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8933 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8934 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8935 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8936 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
8937 {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
8938 /* enable unsolicited event */
8939 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8940 { } /* end */
8941};
8942
Kailang Yange2757d52008-08-26 13:17:46 +02008943static void alc883_eee1601_inithook(struct hda_codec *codec)
8944{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008945 struct alc_spec *spec = codec->spec;
8946
8947 spec->autocfg.hp_pins[0] = 0x14;
8948 spec->autocfg.speaker_pins[0] = 0x1b;
8949 alc_automute_pin(codec);
Kailang Yange2757d52008-08-26 13:17:46 +02008950}
8951
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008952static struct hda_verb alc889A_mb31_verbs[] = {
8953 /* Init rear pin (used as headphone output) */
8954 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */
8955 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */
8956 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8957 /* Init line pin (used as output in 4ch and 6ch mode) */
8958 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Connect to CLFE */
8959 /* Init line 2 pin (used as headphone out by default) */
8960 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Use as input */
8961 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */
8962 { } /* end */
8963};
8964
8965/* Mute speakers according to the headphone jack state */
8966static void alc889A_mb31_automute(struct hda_codec *codec)
8967{
8968 unsigned int present;
8969
8970 /* Mute only in 2ch or 4ch mode */
8971 if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0)
8972 == 0x00) {
Wu Fengguang864f92b2009-11-18 12:38:02 +08008973 present = snd_hda_jack_detect(codec, 0x15);
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008974 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8975 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8976 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8977 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8978 }
8979}
8980
8981static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
8982{
8983 if ((res >> 26) == ALC880_HP_EVENT)
8984 alc889A_mb31_automute(codec);
8985}
8986
Takashi Iwai4953550a2009-06-30 15:28:30 +02008987
Takashi Iwaicb53c622007-08-10 17:21:45 +02008988#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwai4953550a2009-06-30 15:28:30 +02008989#define alc882_loopbacks alc880_loopbacks
Takashi Iwaicb53c622007-08-10 17:21:45 +02008990#endif
8991
Sasha Alexandrdef319f2009-06-16 16:00:15 -04008992/* pcm configuration: identical with ALC880 */
Takashi Iwai4953550a2009-06-30 15:28:30 +02008993#define alc882_pcm_analog_playback alc880_pcm_analog_playback
8994#define alc882_pcm_analog_capture alc880_pcm_analog_capture
8995#define alc882_pcm_digital_playback alc880_pcm_digital_playback
8996#define alc882_pcm_digital_capture alc880_pcm_digital_capture
8997
8998static hda_nid_t alc883_slave_dig_outs[] = {
8999 ALC1200_DIGOUT_NID, 0,
9000};
9001
9002static hda_nid_t alc1200_slave_dig_outs[] = {
9003 ALC883_DIGOUT_NID, 0,
9004};
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009005
9006/*
9007 * configuration and preset
9008 */
Takashi Iwai4953550a2009-06-30 15:28:30 +02009009static const char *alc882_models[ALC882_MODEL_LAST] = {
9010 [ALC882_3ST_DIG] = "3stack-dig",
9011 [ALC882_6ST_DIG] = "6stack-dig",
9012 [ALC882_ARIMA] = "arima",
9013 [ALC882_W2JC] = "w2jc",
9014 [ALC882_TARGA] = "targa",
9015 [ALC882_ASUS_A7J] = "asus-a7j",
9016 [ALC882_ASUS_A7M] = "asus-a7m",
9017 [ALC885_MACPRO] = "macpro",
9018 [ALC885_MB5] = "mb5",
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009019 [ALC885_MACMINI3] = "macmini3",
Takashi Iwai4953550a2009-06-30 15:28:30 +02009020 [ALC885_MBP3] = "mbp3",
9021 [ALC885_IMAC24] = "imac24",
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009022 [ALC885_IMAC91] = "imac91",
Takashi Iwai4953550a2009-06-30 15:28:30 +02009023 [ALC883_3ST_2ch_DIG] = "3stack-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009024 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
9025 [ALC883_3ST_6ch] = "3stack-6ch",
Takashi Iwai4953550a2009-06-30 15:28:30 +02009026 [ALC883_6ST_DIG] = "alc883-6stack-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009027 [ALC883_TARGA_DIG] = "targa-dig",
9028 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
David Heidelberger64a8be72009-06-08 16:15:18 +02009029 [ALC883_TARGA_8ch_DIG] = "targa-8ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009030 [ALC883_ACER] = "acer",
Tobin Davis2880a8672007-08-07 11:50:26 +02009031 [ALC883_ACER_ASPIRE] = "acer-aspire",
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009032 [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g",
Takashi Iwaib1a91462009-06-21 10:56:44 +02009033 [ALC888_ACER_ASPIRE_6530G] = "acer-aspire-6530g",
Hector Martin3b315d72009-06-02 10:54:19 +02009034 [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g",
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009035 [ALC888_ACER_ASPIRE_7730G] = "acer-aspire-7730g",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009036 [ALC883_MEDION] = "medion",
Kailang Yang272a5272007-05-14 11:00:38 +02009037 [ALC883_MEDION_MD2] = "medion-md2",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009038 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009039 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02009040 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
9041 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yange2757d52008-08-26 13:17:46 +02009042 [ALC888_LENOVO_SKY] = "lenovo-sky",
Kailang Yang189609a2007-08-20 11:31:23 +02009043 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009044 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009045 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009046 [ALC883_MITAC] = "mitac",
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309047 [ALC883_CLEVO_M540R] = "clevo-m540r",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009048 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +01009049 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009050 [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
Jiang zhe17bba1b2008-06-04 12:11:07 +02009051 [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009052 [ALC889A_INTEL] = "intel-alc889a",
9053 [ALC889_INTEL] = "intel-x58",
Wu Fengguang3ab90932008-11-17 09:51:09 +01009054 [ALC1200_ASUS_P5Q] = "asus-p5q",
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009055 [ALC889A_MB31] = "mb31",
Guido Günther3e1647c2009-06-05 00:47:26 +02009056 [ALC883_SONY_VAIO_TT] = "sony-vaio-tt",
Takashi Iwai4953550a2009-06-30 15:28:30 +02009057 [ALC882_AUTO] = "auto",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009058};
9059
Takashi Iwai4953550a2009-06-30 15:28:30 +02009060static struct snd_pci_quirk alc882_cfg_tbl[] = {
9061 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
9062
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009063 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
Takashi Iwai69e50282008-11-03 10:07:43 +01009064 SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
Takashi Iwai9b6682f2009-03-23 22:50:52 +01009065 SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009066 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
9067 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
Jaroslav Kysela0b18cb12008-07-28 17:07:07 +02009068 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009069 SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
9070 ALC888_ACER_ASPIRE_4930G),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01009071 SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
Takashi Iwai83dd7402009-11-24 08:57:53 +01009072 ALC888_ACER_ASPIRE_4930G),
Hector Martin3b315d72009-06-02 10:54:19 +02009073 SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
9074 ALC888_ACER_ASPIRE_8930G),
Takashi Iwaie46b0c82009-06-13 10:16:43 +02009075 SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
9076 ALC888_ACER_ASPIRE_8930G),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009077 SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO),
9078 SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01009079 SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
Takashi Iwaidde65352009-06-25 08:25:35 +02009080 ALC888_ACER_ASPIRE_6530G),
Juan Jesus Garcia de Soriacc374c42009-02-23 08:11:59 +01009081 SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
Tony Vroond2fd4b02009-06-21 00:40:10 +01009082 ALC888_ACER_ASPIRE_6530G),
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009083 SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
9084 ALC888_ACER_ASPIRE_7730G),
Takashi Iwai22b530e2009-05-13 11:32:52 +02009085 /* default Acer -- disabled as it causes more problems.
9086 * model=auto should work fine now
9087 */
9088 /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */
Takashi Iwai4953550a2009-06-30 15:28:30 +02009089
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009090 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009091
Tobin Davisfebe3372007-06-12 11:27:46 +02009092 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009093 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
9094 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +01009095 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Chris Bagwell06bf3e12009-01-01 10:32:08 +01009096 SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
Herton Ronaldo Krzesinski7ec30f02009-03-04 14:22:52 -03009097 SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009098
9099 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
9100 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
9101 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Kailang Yanga01c30c2008-10-15 11:14:58 +02009102 SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009103 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
9104 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
9105 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009106 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Mackenzie Morgan44a678d2009-02-10 17:13:43 +01009107 SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
Wu Fengguang3ab90932008-11-17 09:51:09 +01009108 SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
Kailang Yange2757d52008-08-26 13:17:46 +02009109 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009110
9111 SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
Travis Place97ec7102008-05-23 18:31:46 +02009112 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009113 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009114 SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009115 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
9116 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
Kailang Yange2757d52008-08-26 13:17:46 +02009117 SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009118 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009119 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
9120
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009121 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
9122 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
9123 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009124 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
Takashi Iwai2fef62c2009-12-18 08:48:42 +01009125 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC882_AUTO),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009126 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009127 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01009128 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009129 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
9130 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
9131 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
9132 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
9133 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
9134 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009135 SND_PCI_QUIRK(0x1462, 0x42cd, "MSI", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009136 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
9137 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
9138 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
David Heidelberger64a8be72009-06-08 16:15:18 +02009139 SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009140 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
9141 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02009142 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Takashi Iwaiee095432008-11-25 15:03:38 +01009143 SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +01009144 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01009145 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02009146 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Sasha Alexandrdf01b8a2009-06-16 14:46:17 -04009147 SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009148 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009149 SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009150
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009151 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009152 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
9153 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309154 SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R),
Takashi Iwaidea0a502009-02-09 17:14:52 +01009155 SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04009156 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009157 /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009158 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009159 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
Takashi Iwaif67d8172009-02-04 23:30:19 +01009160 ALC883_FUJITSU_PI2515),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009161 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009162 ALC888_FUJITSU_XA3530),
Kailang Yang272a5272007-05-14 11:00:38 +02009163 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02009164 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009165 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
9166 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yange2757d52008-08-26 13:17:46 +02009167 SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
Kailang Yang272a5272007-05-14 11:00:38 +02009168 SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
Takashi Iwai959973b2008-11-05 11:30:56 +01009169 SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01009170 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02009171 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009172
Jiang zhe17bba1b2008-06-04 12:11:07 +02009173 SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
9174 SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009175 SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009176 SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL),
9177 SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL),
9178 SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009179 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009180
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009181 {}
9182};
9183
Takashi Iwai4953550a2009-06-30 15:28:30 +02009184/* codec SSID table for Intel Mac */
9185static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
9186 SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3),
9187 SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3),
9188 SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3),
9189 SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO),
9190 SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24),
9191 SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24),
9192 SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3),
9193 SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
9194 SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
9195 SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009196 SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009197 SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -05009198 /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2,
9199 * so apparently no perfect solution yet
Takashi Iwai4953550a2009-06-30 15:28:30 +02009200 */
9201 SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -05009202 SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5),
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009203 SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC885_MACMINI3),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009204 {} /* terminator */
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08009205};
9206
Takashi Iwai4953550a2009-06-30 15:28:30 +02009207static struct alc_config_preset alc882_presets[] = {
9208 [ALC882_3ST_DIG] = {
9209 .mixers = { alc882_base_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009210 .init_verbs = { alc882_base_init_verbs,
9211 alc882_adc1_init_verbs },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009212 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9213 .dac_nids = alc882_dac_nids,
9214 .dig_out_nid = ALC882_DIGOUT_NID,
9215 .dig_in_nid = ALC882_DIGIN_NID,
9216 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
9217 .channel_mode = alc882_ch_modes,
9218 .need_dac_fix = 1,
9219 .input_mux = &alc882_capture_source,
9220 },
9221 [ALC882_6ST_DIG] = {
9222 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009223 .init_verbs = { alc882_base_init_verbs,
9224 alc882_adc1_init_verbs },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009225 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9226 .dac_nids = alc882_dac_nids,
9227 .dig_out_nid = ALC882_DIGOUT_NID,
9228 .dig_in_nid = ALC882_DIGIN_NID,
9229 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
9230 .channel_mode = alc882_sixstack_modes,
9231 .input_mux = &alc882_capture_source,
9232 },
9233 [ALC882_ARIMA] = {
9234 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009235 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9236 alc882_eapd_verbs },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009237 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9238 .dac_nids = alc882_dac_nids,
9239 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
9240 .channel_mode = alc882_sixstack_modes,
9241 .input_mux = &alc882_capture_source,
9242 },
9243 [ALC882_W2JC] = {
9244 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009245 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9246 alc882_eapd_verbs, alc880_gpio1_init_verbs },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009247 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9248 .dac_nids = alc882_dac_nids,
9249 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
9250 .channel_mode = alc880_threestack_modes,
9251 .need_dac_fix = 1,
9252 .input_mux = &alc882_capture_source,
9253 .dig_out_nid = ALC882_DIGOUT_NID,
9254 },
9255 [ALC885_MBP3] = {
9256 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
9257 .init_verbs = { alc885_mbp3_init_verbs,
9258 alc880_gpio1_init_verbs },
Takashi Iwaibe0ae922009-08-31 08:27:10 +02009259 .num_dacs = 2,
Takashi Iwai4953550a2009-06-30 15:28:30 +02009260 .dac_nids = alc882_dac_nids,
Takashi Iwaibe0ae922009-08-31 08:27:10 +02009261 .hp_nid = 0x04,
9262 .channel_mode = alc885_mbp_4ch_modes,
9263 .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009264 .input_mux = &alc882_capture_source,
9265 .dig_out_nid = ALC882_DIGOUT_NID,
9266 .dig_in_nid = ALC882_DIGIN_NID,
9267 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009268 .setup = alc885_mbp3_setup,
9269 .init_hook = alc_automute_amp,
Takashi Iwai4953550a2009-06-30 15:28:30 +02009270 },
9271 [ALC885_MB5] = {
9272 .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
9273 .init_verbs = { alc885_mb5_init_verbs,
9274 alc880_gpio1_init_verbs },
9275 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9276 .dac_nids = alc882_dac_nids,
9277 .channel_mode = alc885_mb5_6ch_modes,
9278 .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
9279 .input_mux = &mb5_capture_source,
9280 .dig_out_nid = ALC882_DIGOUT_NID,
9281 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +01009282 .unsol_event = alc_automute_amp_unsol_event,
9283 .setup = alc885_mb5_setup,
9284 .init_hook = alc_automute_amp,
Takashi Iwai4953550a2009-06-30 15:28:30 +02009285 },
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009286 [ALC885_MACMINI3] = {
9287 .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer },
9288 .init_verbs = { alc885_macmini3_init_verbs,
9289 alc880_gpio1_init_verbs },
9290 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9291 .dac_nids = alc882_dac_nids,
9292 .channel_mode = alc885_macmini3_6ch_modes,
9293 .num_channel_mode = ARRAY_SIZE(alc885_macmini3_6ch_modes),
9294 .input_mux = &macmini3_capture_source,
9295 .dig_out_nid = ALC882_DIGOUT_NID,
9296 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +01009297 .unsol_event = alc_automute_amp_unsol_event,
9298 .setup = alc885_macmini3_setup,
9299 .init_hook = alc_automute_amp,
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009300 },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009301 [ALC885_MACPRO] = {
9302 .mixers = { alc882_macpro_mixer },
9303 .init_verbs = { alc882_macpro_init_verbs },
9304 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9305 .dac_nids = alc882_dac_nids,
9306 .dig_out_nid = ALC882_DIGOUT_NID,
9307 .dig_in_nid = ALC882_DIGIN_NID,
9308 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
9309 .channel_mode = alc882_ch_modes,
9310 .input_mux = &alc882_capture_source,
9311 .init_hook = alc885_macpro_init_hook,
9312 },
9313 [ALC885_IMAC24] = {
9314 .mixers = { alc885_imac24_mixer },
9315 .init_verbs = { alc885_imac24_init_verbs },
9316 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9317 .dac_nids = alc882_dac_nids,
9318 .dig_out_nid = ALC882_DIGOUT_NID,
9319 .dig_in_nid = ALC882_DIGIN_NID,
9320 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
9321 .channel_mode = alc882_ch_modes,
9322 .input_mux = &alc882_capture_source,
9323 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009324 .setup = alc885_imac24_setup,
Takashi Iwai4953550a2009-06-30 15:28:30 +02009325 .init_hook = alc885_imac24_init_hook,
9326 },
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009327 [ALC885_IMAC91] = {
9328 .mixers = { alc885_imac91_mixer, alc882_chmode_mixer },
9329 .init_verbs = { alc885_imac91_init_verbs,
9330 alc880_gpio1_init_verbs },
9331 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9332 .dac_nids = alc882_dac_nids,
9333 .channel_mode = alc885_mbp_4ch_modes,
9334 .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes),
9335 .input_mux = &alc882_capture_source,
9336 .dig_out_nid = ALC882_DIGOUT_NID,
9337 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +01009338 .unsol_event = alc_automute_amp_unsol_event,
9339 .setup = alc885_imac91_setup,
9340 .init_hook = alc_automute_amp,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009341 },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009342 [ALC882_TARGA] = {
9343 .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009344 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
Takashi Iwai31909b82009-07-10 12:33:48 +02009345 alc880_gpio3_init_verbs, alc882_targa_verbs},
Takashi Iwai4953550a2009-06-30 15:28:30 +02009346 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9347 .dac_nids = alc882_dac_nids,
9348 .dig_out_nid = ALC882_DIGOUT_NID,
9349 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
9350 .adc_nids = alc882_adc_nids,
9351 .capsrc_nids = alc882_capsrc_nids,
9352 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
9353 .channel_mode = alc882_3ST_6ch_modes,
9354 .need_dac_fix = 1,
9355 .input_mux = &alc882_capture_source,
9356 .unsol_event = alc882_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009357 .setup = alc882_targa_setup,
9358 .init_hook = alc882_targa_automute,
Takashi Iwai4953550a2009-06-30 15:28:30 +02009359 },
9360 [ALC882_ASUS_A7J] = {
9361 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009362 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9363 alc882_asus_a7j_verbs},
Takashi Iwai4953550a2009-06-30 15:28:30 +02009364 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9365 .dac_nids = alc882_dac_nids,
9366 .dig_out_nid = ALC882_DIGOUT_NID,
9367 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
9368 .adc_nids = alc882_adc_nids,
9369 .capsrc_nids = alc882_capsrc_nids,
9370 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
9371 .channel_mode = alc882_3ST_6ch_modes,
9372 .need_dac_fix = 1,
9373 .input_mux = &alc882_capture_source,
9374 },
9375 [ALC882_ASUS_A7M] = {
9376 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009377 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9378 alc882_eapd_verbs, alc880_gpio1_init_verbs,
Takashi Iwai4953550a2009-06-30 15:28:30 +02009379 alc882_asus_a7m_verbs },
9380 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9381 .dac_nids = alc882_dac_nids,
9382 .dig_out_nid = ALC882_DIGOUT_NID,
9383 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
9384 .channel_mode = alc880_threestack_modes,
9385 .need_dac_fix = 1,
9386 .input_mux = &alc882_capture_source,
9387 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009388 [ALC883_3ST_2ch_DIG] = {
9389 .mixers = { alc883_3ST_2ch_mixer },
9390 .init_verbs = { alc883_init_verbs },
9391 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9392 .dac_nids = alc883_dac_nids,
9393 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009394 .dig_in_nid = ALC883_DIGIN_NID,
9395 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9396 .channel_mode = alc883_3ST_2ch_modes,
9397 .input_mux = &alc883_capture_source,
9398 },
9399 [ALC883_3ST_6ch_DIG] = {
9400 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9401 .init_verbs = { alc883_init_verbs },
9402 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9403 .dac_nids = alc883_dac_nids,
9404 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009405 .dig_in_nid = ALC883_DIGIN_NID,
9406 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9407 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02009408 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009409 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009410 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009411 [ALC883_3ST_6ch] = {
9412 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9413 .init_verbs = { alc883_init_verbs },
9414 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9415 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009416 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9417 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02009418 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009419 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009420 },
Jiang zhe17bba1b2008-06-04 12:11:07 +02009421 [ALC883_3ST_6ch_INTEL] = {
9422 .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
9423 .init_verbs = { alc883_init_verbs },
9424 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9425 .dac_nids = alc883_dac_nids,
9426 .dig_out_nid = ALC883_DIGOUT_NID,
9427 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08009428 .slave_dig_outs = alc883_slave_dig_outs,
Jiang zhe17bba1b2008-06-04 12:11:07 +02009429 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
9430 .channel_mode = alc883_3ST_6ch_intel_modes,
9431 .need_dac_fix = 1,
9432 .input_mux = &alc883_3stack_6ch_intel,
9433 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009434 [ALC889A_INTEL] = {
9435 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +02009436 .init_verbs = { alc885_init_verbs, alc885_init_input_verbs,
9437 alc_hp15_unsol_verbs },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009438 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9439 .dac_nids = alc883_dac_nids,
9440 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
9441 .adc_nids = alc889_adc_nids,
9442 .dig_out_nid = ALC883_DIGOUT_NID,
9443 .dig_in_nid = ALC883_DIGIN_NID,
9444 .slave_dig_outs = alc883_slave_dig_outs,
9445 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
9446 .channel_mode = alc889_8ch_intel_modes,
9447 .capsrc_nids = alc889_capsrc_nids,
9448 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009449 .setup = alc889_automute_setup,
9450 .init_hook = alc_automute_amp,
Wu Fengguang6732bd02009-07-30 09:19:14 +02009451 .unsol_event = alc_automute_amp_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009452 .need_dac_fix = 1,
9453 },
9454 [ALC889_INTEL] = {
9455 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
9456 .init_verbs = { alc885_init_verbs, alc889_init_input_verbs,
Wu Fengguang6732bd02009-07-30 09:19:14 +02009457 alc889_eapd_verbs, alc_hp15_unsol_verbs},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009458 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9459 .dac_nids = alc883_dac_nids,
9460 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
9461 .adc_nids = alc889_adc_nids,
9462 .dig_out_nid = ALC883_DIGOUT_NID,
9463 .dig_in_nid = ALC883_DIGIN_NID,
9464 .slave_dig_outs = alc883_slave_dig_outs,
9465 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
9466 .channel_mode = alc889_8ch_intel_modes,
9467 .capsrc_nids = alc889_capsrc_nids,
9468 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009469 .setup = alc889_automute_setup,
Wu Fengguang6732bd02009-07-30 09:19:14 +02009470 .init_hook = alc889_intel_init_hook,
9471 .unsol_event = alc_automute_amp_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009472 .need_dac_fix = 1,
9473 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009474 [ALC883_6ST_DIG] = {
9475 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
9476 .init_verbs = { alc883_init_verbs },
9477 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9478 .dac_nids = alc883_dac_nids,
9479 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009480 .dig_in_nid = ALC883_DIGIN_NID,
9481 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9482 .channel_mode = alc883_sixstack_modes,
9483 .input_mux = &alc883_capture_source,
9484 },
Kailang Yangccc656c2006-10-17 12:32:26 +02009485 [ALC883_TARGA_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -04009486 .mixers = { alc883_targa_mixer, alc883_chmode_mixer },
David Heidelberger005b1072009-07-09 18:45:46 +02009487 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
9488 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +02009489 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9490 .dac_nids = alc883_dac_nids,
9491 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02009492 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9493 .channel_mode = alc883_3ST_6ch_modes,
9494 .need_dac_fix = 1,
9495 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -04009496 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009497 .setup = alc882_targa_setup,
9498 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02009499 },
9500 [ALC883_TARGA_2ch_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -04009501 .mixers = { alc883_targa_2ch_mixer},
David Heidelberger005b1072009-07-09 18:45:46 +02009502 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
9503 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +02009504 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9505 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009506 .adc_nids = alc883_adc_nids_alt,
9507 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +01009508 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangccc656c2006-10-17 12:32:26 +02009509 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02009510 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9511 .channel_mode = alc883_3ST_2ch_modes,
9512 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -04009513 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009514 .setup = alc882_targa_setup,
9515 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02009516 },
David Heidelberger64a8be72009-06-08 16:15:18 +02009517 [ALC883_TARGA_8ch_DIG] = {
Takashi Iwaib99dba32009-09-17 18:23:00 +02009518 .mixers = { alc883_targa_mixer, alc883_targa_8ch_mixer,
9519 alc883_chmode_mixer },
David Heidelberger64a8be72009-06-08 16:15:18 +02009520 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
Sasha Alexandrc2592492009-06-16 14:52:54 -04009521 alc883_targa_verbs },
David Heidelberger64a8be72009-06-08 16:15:18 +02009522 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9523 .dac_nids = alc883_dac_nids,
9524 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
9525 .adc_nids = alc883_adc_nids_rev,
9526 .capsrc_nids = alc883_capsrc_nids_rev,
9527 .dig_out_nid = ALC883_DIGOUT_NID,
9528 .dig_in_nid = ALC883_DIGIN_NID,
9529 .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes),
9530 .channel_mode = alc883_4ST_8ch_modes,
9531 .need_dac_fix = 1,
9532 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -04009533 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009534 .setup = alc882_targa_setup,
9535 .init_hook = alc882_targa_automute,
David Heidelberger64a8be72009-06-08 16:15:18 +02009536 },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02009537 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02009538 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02009539 /* On TravelMate laptops, GPIO 0 enables the internal speaker
9540 * and the headphone jack. Turn this on and rely on the
9541 * standard mute methods whenever the user wants to turn
9542 * these outputs off.
9543 */
9544 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
9545 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9546 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02009547 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9548 .channel_mode = alc883_3ST_2ch_modes,
9549 .input_mux = &alc883_capture_source,
9550 },
Tobin Davis2880a8672007-08-07 11:50:26 +02009551 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02009552 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +02009553 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a8672007-08-07 11:50:26 +02009554 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9555 .dac_nids = alc883_dac_nids,
9556 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a8672007-08-07 11:50:26 +02009557 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9558 .channel_mode = alc883_3ST_2ch_modes,
9559 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009560 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009561 .setup = alc883_acer_aspire_setup,
9562 .init_hook = alc_automute_amp,
Kailang Yangd1a991a2007-08-15 16:21:59 +02009563 },
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009564 [ALC888_ACER_ASPIRE_4930G] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009565 .mixers = { alc888_base_mixer,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009566 alc883_chmode_mixer },
9567 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
9568 alc888_acer_aspire_4930g_verbs },
9569 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9570 .dac_nids = alc883_dac_nids,
9571 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
9572 .adc_nids = alc883_adc_nids_rev,
9573 .capsrc_nids = alc883_capsrc_nids_rev,
9574 .dig_out_nid = ALC883_DIGOUT_NID,
9575 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9576 .channel_mode = alc883_3ST_6ch_modes,
9577 .need_dac_fix = 1,
Łukasz Wojniłowicz973b8cb2010-01-24 14:12:37 +01009578 .const_channel_count = 6,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009579 .num_mux_defs =
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009580 ARRAY_SIZE(alc888_2_capture_sources),
9581 .input_mux = alc888_2_capture_sources,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009582 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009583 .setup = alc888_acer_aspire_4930g_setup,
9584 .init_hook = alc_automute_amp,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009585 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01009586 [ALC888_ACER_ASPIRE_6530G] = {
9587 .mixers = { alc888_acer_aspire_6530_mixer },
9588 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
9589 alc888_acer_aspire_6530g_verbs },
9590 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9591 .dac_nids = alc883_dac_nids,
9592 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
9593 .adc_nids = alc883_adc_nids_rev,
9594 .capsrc_nids = alc883_capsrc_nids_rev,
9595 .dig_out_nid = ALC883_DIGOUT_NID,
9596 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9597 .channel_mode = alc883_3ST_2ch_modes,
9598 .num_mux_defs =
9599 ARRAY_SIZE(alc888_2_capture_sources),
9600 .input_mux = alc888_acer_aspire_6530_sources,
9601 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009602 .setup = alc888_acer_aspire_6530g_setup,
9603 .init_hook = alc_automute_amp,
Tony Vroond2fd4b02009-06-21 00:40:10 +01009604 },
Hector Martin3b315d72009-06-02 10:54:19 +02009605 [ALC888_ACER_ASPIRE_8930G] = {
Hector Martin556eea92009-12-20 22:51:23 +01009606 .mixers = { alc889_acer_aspire_8930g_mixer,
Hector Martin3b315d72009-06-02 10:54:19 +02009607 alc883_chmode_mixer },
9608 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
Hector Martin0f86a222009-12-20 22:51:18 +01009609 alc889_acer_aspire_8930g_verbs,
9610 alc889_eapd_verbs},
Hector Martin3b315d72009-06-02 10:54:19 +02009611 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9612 .dac_nids = alc883_dac_nids,
Hector Martin018df412009-06-04 00:13:40 +02009613 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
9614 .adc_nids = alc889_adc_nids,
9615 .capsrc_nids = alc889_capsrc_nids,
Hector Martin3b315d72009-06-02 10:54:19 +02009616 .dig_out_nid = ALC883_DIGOUT_NID,
9617 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9618 .channel_mode = alc883_3ST_6ch_modes,
9619 .need_dac_fix = 1,
9620 .const_channel_count = 6,
9621 .num_mux_defs =
Hector Martin018df412009-06-04 00:13:40 +02009622 ARRAY_SIZE(alc889_capture_sources),
9623 .input_mux = alc889_capture_sources,
Hector Martin3b315d72009-06-02 10:54:19 +02009624 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009625 .setup = alc889_acer_aspire_8930g_setup,
9626 .init_hook = alc_automute_amp,
Hector Martinf5de24b2009-12-20 22:51:31 +01009627#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -05009628 .power_hook = alc_power_eapd,
Hector Martinf5de24b2009-12-20 22:51:31 +01009629#endif
Hector Martin3b315d72009-06-02 10:54:19 +02009630 },
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009631 [ALC888_ACER_ASPIRE_7730G] = {
9632 .mixers = { alc883_3ST_6ch_mixer,
9633 alc883_chmode_mixer },
9634 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
9635 alc888_acer_aspire_7730G_verbs },
9636 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9637 .dac_nids = alc883_dac_nids,
9638 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
9639 .adc_nids = alc883_adc_nids_rev,
9640 .capsrc_nids = alc883_capsrc_nids_rev,
9641 .dig_out_nid = ALC883_DIGOUT_NID,
9642 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9643 .channel_mode = alc883_3ST_6ch_modes,
9644 .need_dac_fix = 1,
9645 .const_channel_count = 6,
9646 .input_mux = &alc883_capture_source,
9647 .unsol_event = alc_automute_amp_unsol_event,
9648 .setup = alc888_acer_aspire_6530g_setup,
9649 .init_hook = alc_automute_amp,
9650 },
Tobin Davisc07584c2006-10-13 12:32:16 +02009651 [ALC883_MEDION] = {
9652 .mixers = { alc883_fivestack_mixer,
9653 alc883_chmode_mixer },
9654 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01009655 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +02009656 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9657 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009658 .adc_nids = alc883_adc_nids_alt,
9659 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +01009660 .capsrc_nids = alc883_capsrc_nids,
Tobin Davisc07584c2006-10-13 12:32:16 +02009661 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9662 .channel_mode = alc883_sixstack_modes,
9663 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01009664 },
Kailang Yang272a5272007-05-14 11:00:38 +02009665 [ALC883_MEDION_MD2] = {
9666 .mixers = { alc883_medion_md2_mixer},
9667 .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
9668 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9669 .dac_nids = alc883_dac_nids,
9670 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02009671 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9672 .channel_mode = alc883_3ST_2ch_modes,
9673 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009674 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009675 .setup = alc883_medion_md2_setup,
9676 .init_hook = alc_automute_amp,
Kailang Yangea1fb292008-08-26 12:58:38 +02009677 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01009678 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02009679 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01009680 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
9681 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9682 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01009683 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9684 .channel_mode = alc883_3ST_2ch_modes,
9685 .input_mux = &alc883_capture_source,
9686 },
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309687 [ALC883_CLEVO_M540R] = {
9688 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9689 .init_verbs = { alc883_init_verbs, alc883_clevo_m540r_verbs },
9690 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9691 .dac_nids = alc883_dac_nids,
9692 .dig_out_nid = ALC883_DIGOUT_NID,
9693 .dig_in_nid = ALC883_DIGIN_NID,
9694 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_clevo_modes),
9695 .channel_mode = alc883_3ST_6ch_clevo_modes,
9696 .need_dac_fix = 1,
9697 .input_mux = &alc883_capture_source,
9698 /* This machine has the hardware HP auto-muting, thus
9699 * we need no software mute via unsol event
9700 */
9701 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009702 [ALC883_CLEVO_M720] = {
9703 .mixers = { alc883_clevo_m720_mixer },
9704 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +01009705 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9706 .dac_nids = alc883_dac_nids,
9707 .dig_out_nid = ALC883_DIGOUT_NID,
9708 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9709 .channel_mode = alc883_3ST_2ch_modes,
9710 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009711 .unsol_event = alc883_clevo_m720_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009712 .setup = alc883_clevo_m720_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009713 .init_hook = alc883_clevo_m720_init_hook,
Jiang zhe368c7a92008-03-04 11:20:33 +01009714 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009715 [ALC883_LENOVO_101E_2ch] = {
9716 .mixers = { alc883_lenovo_101e_2ch_mixer},
9717 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
9718 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9719 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009720 .adc_nids = alc883_adc_nids_alt,
9721 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +01009722 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009723 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9724 .channel_mode = alc883_3ST_2ch_modes,
9725 .input_mux = &alc883_lenovo_101e_capture_source,
9726 .unsol_event = alc883_lenovo_101e_unsol_event,
9727 .init_hook = alc883_lenovo_101e_all_automute,
9728 },
Kailang Yang272a5272007-05-14 11:00:38 +02009729 [ALC883_LENOVO_NB0763] = {
9730 .mixers = { alc883_lenovo_nb0763_mixer },
9731 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
9732 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9733 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02009734 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9735 .channel_mode = alc883_3ST_2ch_modes,
9736 .need_dac_fix = 1,
9737 .input_mux = &alc883_lenovo_nb0763_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009738 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009739 .setup = alc883_medion_md2_setup,
9740 .init_hook = alc_automute_amp,
Kailang Yang272a5272007-05-14 11:00:38 +02009741 },
9742 [ALC888_LENOVO_MS7195_DIG] = {
9743 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9744 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
9745 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9746 .dac_nids = alc883_dac_nids,
9747 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02009748 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9749 .channel_mode = alc883_3ST_6ch_modes,
9750 .need_dac_fix = 1,
9751 .input_mux = &alc883_capture_source,
9752 .unsol_event = alc883_lenovo_ms7195_unsol_event,
9753 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +02009754 },
9755 [ALC883_HAIER_W66] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -04009756 .mixers = { alc883_targa_2ch_mixer},
Kailang Yang189609a2007-08-20 11:31:23 +02009757 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
9758 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9759 .dac_nids = alc883_dac_nids,
9760 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +02009761 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9762 .channel_mode = alc883_3ST_2ch_modes,
9763 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009764 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009765 .setup = alc883_haier_w66_setup,
9766 .init_hook = alc_automute_amp,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01009767 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009768 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01009769 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009770 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009771 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9772 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009773 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
9774 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009775 .need_dac_fix = 1,
9776 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009777 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009778 .setup = alc888_3st_hp_setup,
9779 .init_hook = alc_automute_amp,
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009780 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009781 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +01009782 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009783 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
9784 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9785 .dac_nids = alc883_dac_nids,
9786 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009787 .dig_in_nid = ALC883_DIGIN_NID,
9788 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9789 .channel_mode = alc883_sixstack_modes,
9790 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009791 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009792 .setup = alc888_6st_dell_setup,
9793 .init_hook = alc_automute_amp,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009794 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009795 [ALC883_MITAC] = {
9796 .mixers = { alc883_mitac_mixer },
9797 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
9798 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9799 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009800 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9801 .channel_mode = alc883_3ST_2ch_modes,
9802 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009803 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009804 .setup = alc883_mitac_setup,
9805 .init_hook = alc_automute_amp,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009806 },
Jiang zhefb97dc62008-03-06 11:07:11 +01009807 [ALC883_FUJITSU_PI2515] = {
9808 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
9809 .init_verbs = { alc883_init_verbs,
9810 alc883_2ch_fujitsu_pi2515_verbs},
9811 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9812 .dac_nids = alc883_dac_nids,
9813 .dig_out_nid = ALC883_DIGOUT_NID,
9814 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9815 .channel_mode = alc883_3ST_2ch_modes,
9816 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009817 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009818 .setup = alc883_2ch_fujitsu_pi2515_setup,
9819 .init_hook = alc_automute_amp,
Jiang zhefb97dc62008-03-06 11:07:11 +01009820 },
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009821 [ALC888_FUJITSU_XA3530] = {
9822 .mixers = { alc888_base_mixer, alc883_chmode_mixer },
9823 .init_verbs = { alc883_init_verbs,
9824 alc888_fujitsu_xa3530_verbs },
9825 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9826 .dac_nids = alc883_dac_nids,
9827 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
9828 .adc_nids = alc883_adc_nids_rev,
9829 .capsrc_nids = alc883_capsrc_nids_rev,
9830 .dig_out_nid = ALC883_DIGOUT_NID,
9831 .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes),
9832 .channel_mode = alc888_4ST_8ch_intel_modes,
9833 .num_mux_defs =
9834 ARRAY_SIZE(alc888_2_capture_sources),
9835 .input_mux = alc888_2_capture_sources,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009836 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009837 .setup = alc888_fujitsu_xa3530_setup,
9838 .init_hook = alc_automute_amp,
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009839 },
Kailang Yange2757d52008-08-26 13:17:46 +02009840 [ALC888_LENOVO_SKY] = {
9841 .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
9842 .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
9843 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9844 .dac_nids = alc883_dac_nids,
9845 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yange2757d52008-08-26 13:17:46 +02009846 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9847 .channel_mode = alc883_sixstack_modes,
9848 .need_dac_fix = 1,
9849 .input_mux = &alc883_lenovo_sky_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009850 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009851 .setup = alc888_lenovo_sky_setup,
9852 .init_hook = alc_automute_amp,
Kailang Yange2757d52008-08-26 13:17:46 +02009853 },
9854 [ALC888_ASUS_M90V] = {
9855 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9856 .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
9857 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9858 .dac_nids = alc883_dac_nids,
9859 .dig_out_nid = ALC883_DIGOUT_NID,
9860 .dig_in_nid = ALC883_DIGIN_NID,
9861 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9862 .channel_mode = alc883_3ST_6ch_modes,
9863 .need_dac_fix = 1,
9864 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009865 .unsol_event = alc_sku_unsol_event,
9866 .setup = alc883_mode2_setup,
9867 .init_hook = alc_inithook,
Kailang Yange2757d52008-08-26 13:17:46 +02009868 },
9869 [ALC888_ASUS_EEE1601] = {
9870 .mixers = { alc883_asus_eee1601_mixer },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009871 .cap_mixer = alc883_asus_eee1601_cap_mixer,
Kailang Yange2757d52008-08-26 13:17:46 +02009872 .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
9873 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9874 .dac_nids = alc883_dac_nids,
9875 .dig_out_nid = ALC883_DIGOUT_NID,
9876 .dig_in_nid = ALC883_DIGIN_NID,
9877 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9878 .channel_mode = alc883_3ST_2ch_modes,
9879 .need_dac_fix = 1,
9880 .input_mux = &alc883_asus_eee1601_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009881 .unsol_event = alc_sku_unsol_event,
Kailang Yange2757d52008-08-26 13:17:46 +02009882 .init_hook = alc883_eee1601_inithook,
9883 },
Wu Fengguang3ab90932008-11-17 09:51:09 +01009884 [ALC1200_ASUS_P5Q] = {
9885 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
9886 .init_verbs = { alc883_init_verbs },
9887 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9888 .dac_nids = alc883_dac_nids,
9889 .dig_out_nid = ALC1200_DIGOUT_NID,
9890 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangb25c9da2009-02-06 15:02:27 +08009891 .slave_dig_outs = alc1200_slave_dig_outs,
Wu Fengguang3ab90932008-11-17 09:51:09 +01009892 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9893 .channel_mode = alc883_sixstack_modes,
9894 .input_mux = &alc883_capture_source,
9895 },
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009896 [ALC889A_MB31] = {
9897 .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer},
9898 .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs,
9899 alc880_gpio1_init_verbs },
9900 .adc_nids = alc883_adc_nids,
9901 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
Takashi Iwai035eb0c2009-12-17 15:00:26 +01009902 .capsrc_nids = alc883_capsrc_nids,
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009903 .dac_nids = alc883_dac_nids,
9904 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9905 .channel_mode = alc889A_mb31_6ch_modes,
9906 .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes),
9907 .input_mux = &alc889A_mb31_capture_source,
9908 .dig_out_nid = ALC883_DIGOUT_NID,
9909 .unsol_event = alc889A_mb31_unsol_event,
9910 .init_hook = alc889A_mb31_automute,
9911 },
Guido Günther3e1647c2009-06-05 00:47:26 +02009912 [ALC883_SONY_VAIO_TT] = {
9913 .mixers = { alc883_vaiott_mixer },
9914 .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs },
9915 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9916 .dac_nids = alc883_dac_nids,
9917 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9918 .channel_mode = alc883_3ST_2ch_modes,
9919 .input_mux = &alc883_capture_source,
9920 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009921 .setup = alc883_vaiott_setup,
9922 .init_hook = alc_automute_amp,
Guido Günther3e1647c2009-06-05 00:47:26 +02009923 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009924};
9925
9926
9927/*
Takashi Iwai4953550a2009-06-30 15:28:30 +02009928 * Pin config fixes
9929 */
9930enum {
9931 PINFIX_ABIT_AW9D_MAX
9932};
9933
9934static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
9935 { 0x15, 0x01080104 }, /* side */
9936 { 0x16, 0x01011012 }, /* rear */
9937 { 0x17, 0x01016011 }, /* clfe */
9938 { }
9939};
9940
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02009941static const struct alc_fixup alc882_fixups[] = {
9942 [PINFIX_ABIT_AW9D_MAX] = {
9943 .pins = alc882_abit_aw9d_pinfix
9944 },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009945};
9946
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02009947static struct snd_pci_quirk alc882_fixup_tbl[] = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02009948 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
9949 {}
9950};
9951
9952/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009953 * BIOS auto configuration
9954 */
Takashi Iwai05f5f472009-08-25 13:10:18 +02009955static int alc882_auto_create_input_ctls(struct hda_codec *codec,
9956 const struct auto_pin_cfg *cfg)
9957{
9958 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x23, 0x22);
9959}
9960
Takashi Iwai4953550a2009-06-30 15:28:30 +02009961static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009962 hda_nid_t nid, int pin_type,
9963 int dac_idx)
9964{
9965 /* set as output */
9966 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009967 int idx;
9968
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009969 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009970 if (spec->multiout.dac_nids[dac_idx] == 0x25)
9971 idx = 4;
9972 else
9973 idx = spec->multiout.dac_nids[dac_idx] - 2;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009974 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
9975
9976}
9977
Takashi Iwai4953550a2009-06-30 15:28:30 +02009978static void alc882_auto_init_multi_out(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009979{
9980 struct alc_spec *spec = codec->spec;
9981 int i;
9982
9983 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009984 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02009985 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009986 if (nid)
Takashi Iwai4953550a2009-06-30 15:28:30 +02009987 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009988 i);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009989 }
9990}
9991
Takashi Iwai4953550a2009-06-30 15:28:30 +02009992static void alc882_auto_init_hp_out(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009993{
9994 struct alc_spec *spec = codec->spec;
9995 hda_nid_t pin;
9996
Takashi Iwaieb06ed82006-09-20 17:10:27 +02009997 pin = spec->autocfg.hp_pins[0];
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009998 if (pin) /* connect to front */
9999 /* use dac 0 */
Takashi Iwai4953550a2009-06-30 15:28:30 +020010000 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010001 pin = spec->autocfg.speaker_pins[0];
10002 if (pin)
Takashi Iwai4953550a2009-06-30 15:28:30 +020010003 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010004}
10005
Takashi Iwai4953550a2009-06-30 15:28:30 +020010006static void alc882_auto_init_analog_input(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010007{
10008 struct alc_spec *spec = codec->spec;
10009 int i;
10010
10011 for (i = 0; i < AUTO_PIN_LAST; i++) {
10012 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai4953550a2009-06-30 15:28:30 +020010013 if (!nid)
10014 continue;
Takashi Iwai0d971c92009-06-30 16:11:11 +020010015 alc_set_input_pin(codec, nid, i);
Takashi Iwai4953550a2009-06-30 15:28:30 +020010016 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
10017 snd_hda_codec_write(codec, nid, 0,
10018 AC_VERB_SET_AMP_GAIN_MUTE,
10019 AMP_OUT_MUTE);
10020 }
10021}
10022
10023static void alc882_auto_init_input_src(struct hda_codec *codec)
10024{
10025 struct alc_spec *spec = codec->spec;
10026 int c;
10027
10028 for (c = 0; c < spec->num_adc_nids; c++) {
10029 hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
10030 hda_nid_t nid = spec->capsrc_nids[c];
10031 unsigned int mux_idx;
10032 const struct hda_input_mux *imux;
10033 int conns, mute, idx, item;
10034
10035 conns = snd_hda_get_connections(codec, nid, conn_list,
10036 ARRAY_SIZE(conn_list));
10037 if (conns < 0)
10038 continue;
10039 mux_idx = c >= spec->num_mux_defs ? 0 : c;
10040 imux = &spec->input_mux[mux_idx];
10041 for (idx = 0; idx < conns; idx++) {
10042 /* if the current connection is the selected one,
10043 * unmute it as default - otherwise mute it
10044 */
10045 mute = AMP_IN_MUTE(idx);
10046 for (item = 0; item < imux->num_items; item++) {
10047 if (imux->items[item].index == idx) {
10048 if (spec->cur_mux[c] == item)
10049 mute = AMP_IN_UNMUTE(idx);
10050 break;
10051 }
10052 }
10053 /* check if we have a selector or mixer
10054 * we could check for the widget type instead, but
10055 * just check for Amp-In presence (in case of mixer
10056 * without amp-in there is something wrong, this
10057 * function shouldn't be used or capsrc nid is wrong)
10058 */
10059 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010060 snd_hda_codec_write(codec, nid, 0,
10061 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwai4953550a2009-06-30 15:28:30 +020010062 mute);
10063 else if (mute != AMP_IN_MUTE(idx))
10064 snd_hda_codec_write(codec, nid, 0,
10065 AC_VERB_SET_CONNECT_SEL,
10066 idx);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010067 }
10068 }
10069}
10070
Takashi Iwai4953550a2009-06-30 15:28:30 +020010071/* add mic boosts if needed */
10072static int alc_auto_add_mic_boost(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010073{
10074 struct alc_spec *spec = codec->spec;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010075 int err;
10076 hda_nid_t nid;
10077
10078 nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
10079 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
10080 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10081 "Mic Boost",
10082 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
10083 if (err < 0)
10084 return err;
10085 }
10086 nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
10087 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
10088 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10089 "Front Mic Boost",
10090 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
10091 if (err < 0)
10092 return err;
10093 }
10094 return 0;
10095}
10096
10097/* almost identical with ALC880 parser... */
10098static int alc882_parse_auto_config(struct hda_codec *codec)
10099{
10100 struct alc_spec *spec = codec->spec;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010101 static hda_nid_t alc882_ignore[] = { 0x1d, 0 };
10102 int i, err;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010103
Takashi Iwai05f5f472009-08-25 13:10:18 +020010104 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10105 alc882_ignore);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010106 if (err < 0)
10107 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010108 if (!spec->autocfg.line_outs)
10109 return 0; /* can't find valid BIOS pin config */
10110
10111 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
10112 if (err < 0)
10113 return err;
10114 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
10115 if (err < 0)
10116 return err;
10117 err = alc880_auto_create_extra_out(spec,
10118 spec->autocfg.speaker_pins[0],
10119 "Speaker");
10120 if (err < 0)
10121 return err;
10122 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
10123 "Headphone");
10124 if (err < 0)
10125 return err;
10126 err = alc882_auto_create_input_ctls(codec, &spec->autocfg);
10127 if (err < 0)
10128 return err;
10129
10130 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10131
10132 /* check multiple SPDIF-out (for recent codecs) */
10133 for (i = 0; i < spec->autocfg.dig_outs; i++) {
10134 hda_nid_t dig_nid;
10135 err = snd_hda_get_connections(codec,
10136 spec->autocfg.dig_out_pins[i],
10137 &dig_nid, 1);
10138 if (err < 0)
10139 continue;
10140 if (!i)
10141 spec->multiout.dig_out_nid = dig_nid;
10142 else {
10143 spec->multiout.slave_dig_outs = spec->slave_dig_outs;
Roel Kluin71121d9f2009-11-10 20:11:55 +010010144 if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
Takashi Iwai05f5f472009-08-25 13:10:18 +020010145 break;
Roel Kluin71121d9f2009-11-10 20:11:55 +010010146 spec->slave_dig_outs[i - 1] = dig_nid;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010147 }
10148 }
10149 if (spec->autocfg.dig_in_pin)
10150 spec->dig_in_nid = ALC880_DIGIN_NID;
10151
10152 if (spec->kctls.list)
10153 add_mixer(spec, spec->kctls.list);
10154
10155 add_verb(spec, alc883_auto_init_verbs);
10156 /* if ADC 0x07 is available, initialize it, too */
10157 if (get_wcaps_type(get_wcaps(codec, 0x07)) == AC_WID_AUD_IN)
10158 add_verb(spec, alc882_adc1_init_verbs);
10159
10160 spec->num_mux_defs = 1;
10161 spec->input_mux = &spec->private_imux[0];
10162
10163 alc_ssid_check(codec, 0x15, 0x1b, 0x14);
Takashi Iwai776e1842007-08-29 15:07:11 +020010164
10165 err = alc_auto_add_mic_boost(codec);
10166 if (err < 0)
10167 return err;
10168
Takashi Iwai776e1842007-08-29 15:07:11 +020010169 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010170}
10171
10172/* additional initialization for auto-configuration model */
Takashi Iwai4953550a2009-06-30 15:28:30 +020010173static void alc882_auto_init(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010174{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010175 struct alc_spec *spec = codec->spec;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010176 alc882_auto_init_multi_out(codec);
10177 alc882_auto_init_hp_out(codec);
10178 alc882_auto_init_analog_input(codec);
10179 alc882_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010180 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020010181 alc_inithook(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010182}
10183
Takashi Iwai4953550a2009-06-30 15:28:30 +020010184static int patch_alc882(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010185{
10186 struct alc_spec *spec;
10187 int err, board_config;
10188
10189 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
10190 if (spec == NULL)
10191 return -ENOMEM;
10192
10193 codec->spec = spec;
10194
Takashi Iwai4953550a2009-06-30 15:28:30 +020010195 switch (codec->vendor_id) {
10196 case 0x10ec0882:
10197 case 0x10ec0885:
10198 break;
10199 default:
10200 /* ALC883 and variants */
10201 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
10202 break;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010203 }
10204
Takashi Iwai4953550a2009-06-30 15:28:30 +020010205 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
10206 alc882_models,
10207 alc882_cfg_tbl);
10208
10209 if (board_config < 0 || board_config >= ALC882_MODEL_LAST)
10210 board_config = snd_hda_check_board_codec_sid_config(codec,
10211 ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
10212
10213 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020010214 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai4953550a2009-06-30 15:28:30 +020010215 codec->chip_name);
10216 board_config = ALC882_AUTO;
10217 }
10218
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010219 alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups);
Takashi Iwai4953550a2009-06-30 15:28:30 +020010220
10221 if (board_config == ALC882_AUTO) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010222 /* automatic parse from the BIOS config */
Takashi Iwai4953550a2009-06-30 15:28:30 +020010223 err = alc882_parse_auto_config(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010224 if (err < 0) {
10225 alc_free(codec);
10226 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010227 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010228 printk(KERN_INFO
10229 "hda_codec: Cannot set up configuration "
10230 "from BIOS. Using base mode...\n");
Takashi Iwai4953550a2009-06-30 15:28:30 +020010231 board_config = ALC882_3ST_DIG;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010232 }
10233 }
10234
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090010235 err = snd_hda_attach_beep_device(codec, 0x1);
10236 if (err < 0) {
10237 alc_free(codec);
10238 return err;
10239 }
10240
Takashi Iwai4953550a2009-06-30 15:28:30 +020010241 if (board_config != ALC882_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020010242 setup_preset(codec, &alc882_presets[board_config]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010243
Takashi Iwai4953550a2009-06-30 15:28:30 +020010244 spec->stream_analog_playback = &alc882_pcm_analog_playback;
10245 spec->stream_analog_capture = &alc882_pcm_analog_capture;
10246 /* FIXME: setup DAC5 */
10247 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
10248 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
10249
10250 spec->stream_digital_playback = &alc882_pcm_digital_playback;
10251 spec->stream_digital_capture = &alc882_pcm_digital_capture;
10252
10253 if (codec->vendor_id == 0x10ec0888)
Takashi Iwai4a79ba32009-04-22 16:31:35 +020010254 spec->init_amp = ALC_INIT_DEFAULT; /* always initialize */
Takashi Iwai4953550a2009-06-30 15:28:30 +020010255
10256 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010257 int i, j;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010258 spec->num_adc_nids = 0;
10259 for (i = 0; i < ARRAY_SIZE(alc882_adc_nids); i++) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010260 const struct hda_input_mux *imux = spec->input_mux;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010261 hda_nid_t cap;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010262 hda_nid_t items[16];
Takashi Iwai4953550a2009-06-30 15:28:30 +020010263 hda_nid_t nid = alc882_adc_nids[i];
10264 unsigned int wcap = get_wcaps(codec, nid);
10265 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020010266 wcap = get_wcaps_type(wcap);
Takashi Iwai4953550a2009-06-30 15:28:30 +020010267 if (wcap != AC_WID_AUD_IN)
10268 continue;
10269 spec->private_adc_nids[spec->num_adc_nids] = nid;
10270 err = snd_hda_get_connections(codec, nid, &cap, 1);
10271 if (err < 0)
10272 continue;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010273 err = snd_hda_get_connections(codec, cap, items,
10274 ARRAY_SIZE(items));
10275 if (err < 0)
10276 continue;
10277 for (j = 0; j < imux->num_items; j++)
10278 if (imux->items[j].index >= err)
10279 break;
10280 if (j < imux->num_items)
10281 continue;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010282 spec->private_capsrc_nids[spec->num_adc_nids] = cap;
10283 spec->num_adc_nids++;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020010284 }
Takashi Iwai4953550a2009-06-30 15:28:30 +020010285 spec->adc_nids = spec->private_adc_nids;
10286 spec->capsrc_nids = spec->private_capsrc_nids;
Kailang Yang2f893282008-05-27 12:14:47 +020010287 }
10288
Takashi Iwaib59bdf32009-08-11 09:47:30 +020010289 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010010290 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010291
Takashi Iwai2134ea42008-01-10 16:53:55 +010010292 spec->vmaster_nid = 0x0c;
10293
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010294 codec->patch_ops = alc_patch_ops;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010295 if (board_config == ALC882_AUTO)
10296 spec->init_hook = alc882_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020010297#ifdef CONFIG_SND_HDA_POWER_SAVE
10298 if (!spec->loopback.amplist)
Takashi Iwai4953550a2009-06-30 15:28:30 +020010299 spec->loopback.amplist = alc882_loopbacks;
Takashi Iwaicb53c622007-08-10 17:21:45 +020010300#endif
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010301
10302 return 0;
10303}
10304
Takashi Iwai4953550a2009-06-30 15:28:30 +020010305
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010306/*
Kailang Yangdf694da2005-12-05 19:42:22 +010010307 * ALC262 support
10308 */
10309
10310#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
10311#define ALC262_DIGIN_NID ALC880_DIGIN_NID
10312
10313#define alc262_dac_nids alc260_dac_nids
10314#define alc262_adc_nids alc882_adc_nids
10315#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +010010316#define alc262_capsrc_nids alc882_capsrc_nids
10317#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +010010318
10319#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +010010320#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +010010321
Kailang Yang4e555fe2008-08-26 13:05:55 +020010322static hda_nid_t alc262_dmic_adc_nids[1] = {
10323 /* ADC0 */
10324 0x09
10325};
10326
10327static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
10328
Kailang Yangdf694da2005-12-05 19:42:22 +010010329static struct snd_kcontrol_new alc262_base_mixer[] = {
10330 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10331 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10332 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10333 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
10334 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10335 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10336 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10337 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010338 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010010339 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10340 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010341 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010010342 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
10343 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10344 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
10345 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010010346 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +010010347};
10348
Takashi Iwaice875f02008-01-28 18:17:43 +010010349/* update HP, line and mono-out pins according to the master switch */
10350static void alc262_hp_master_update(struct hda_codec *codec)
10351{
10352 struct alc_spec *spec = codec->spec;
10353 int val = spec->master_sw;
10354
10355 /* HP & line-out */
10356 snd_hda_codec_write_cache(codec, 0x1b, 0,
10357 AC_VERB_SET_PIN_WIDGET_CONTROL,
10358 val ? PIN_HP : 0);
10359 snd_hda_codec_write_cache(codec, 0x15, 0,
10360 AC_VERB_SET_PIN_WIDGET_CONTROL,
10361 val ? PIN_HP : 0);
10362 /* mono (speaker) depending on the HP jack sense */
10363 val = val && !spec->jack_present;
10364 snd_hda_codec_write_cache(codec, 0x16, 0,
10365 AC_VERB_SET_PIN_WIDGET_CONTROL,
10366 val ? PIN_OUT : 0);
10367}
10368
10369static void alc262_hp_bpc_automute(struct hda_codec *codec)
10370{
10371 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080010372
10373 spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
Takashi Iwaice875f02008-01-28 18:17:43 +010010374 alc262_hp_master_update(codec);
10375}
10376
10377static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
10378{
10379 if ((res >> 26) != ALC880_HP_EVENT)
10380 return;
10381 alc262_hp_bpc_automute(codec);
10382}
10383
10384static void alc262_hp_wildwest_automute(struct hda_codec *codec)
10385{
10386 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080010387
10388 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaice875f02008-01-28 18:17:43 +010010389 alc262_hp_master_update(codec);
10390}
10391
10392static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
10393 unsigned int res)
10394{
10395 if ((res >> 26) != ALC880_HP_EVENT)
10396 return;
10397 alc262_hp_wildwest_automute(codec);
10398}
10399
Takashi Iwaib72519b2009-05-08 14:31:55 +020010400#define alc262_hp_master_sw_get alc260_hp_master_sw_get
Takashi Iwaice875f02008-01-28 18:17:43 +010010401
10402static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
10403 struct snd_ctl_elem_value *ucontrol)
10404{
10405 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10406 struct alc_spec *spec = codec->spec;
10407 int val = !!*ucontrol->value.integer.value;
10408
10409 if (val == spec->master_sw)
10410 return 0;
10411 spec->master_sw = val;
10412 alc262_hp_master_update(codec);
10413 return 1;
10414}
10415
Takashi Iwaib72519b2009-05-08 14:31:55 +020010416#define ALC262_HP_MASTER_SWITCH \
10417 { \
10418 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
10419 .name = "Master Playback Switch", \
10420 .info = snd_ctl_boolean_mono_info, \
10421 .get = alc262_hp_master_sw_get, \
10422 .put = alc262_hp_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010010423 }, \
10424 { \
10425 .iface = NID_MAPPING, \
10426 .name = "Master Playback Switch", \
10427 .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \
Takashi Iwaib72519b2009-05-08 14:31:55 +020010428 }
10429
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010010430
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010431static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020010432 ALC262_HP_MASTER_SWITCH,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010433 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10434 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10435 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010010436 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
10437 HDA_OUTPUT),
10438 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
10439 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010440 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10441 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010442 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010443 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10444 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010445 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010446 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10447 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10448 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10449 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010450 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
10451 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
10452 { } /* end */
10453};
10454
Kailang Yangcd7509a2007-01-26 18:33:17 +010010455static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020010456 ALC262_HP_MASTER_SWITCH,
Kailang Yangcd7509a2007-01-26 18:33:17 +010010457 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10458 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
10459 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
10460 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010010461 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
10462 HDA_OUTPUT),
10463 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
10464 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010465 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
10466 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010467 HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010468 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
10469 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
10470 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10471 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010472 { } /* end */
10473};
10474
10475static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
10476 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10477 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010478 HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010479 { } /* end */
10480};
10481
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010482/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010483static void alc262_hp_t5735_setup(struct hda_codec *codec)
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010484{
10485 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010486
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010487 spec->autocfg.hp_pins[0] = 0x15;
Takashi Iwaidc99be42010-01-20 08:35:06 +010010488 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010489}
10490
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010491static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010010492 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10493 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010494 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
10495 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10496 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10497 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10498 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10499 { } /* end */
10500};
10501
10502static struct hda_verb alc262_hp_t5735_verbs[] = {
10503 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10504 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10505
10506 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10507 { }
10508};
10509
Kailang Yang8c427222008-01-10 13:03:59 +010010510static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +010010511 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10512 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010010513 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
10514 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010010515 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
10516 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
10517 { } /* end */
10518};
10519
10520static struct hda_verb alc262_hp_rp5700_verbs[] = {
10521 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10522 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10523 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10524 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10525 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10526 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
10527 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10528 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10529 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
10530 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
10531 {}
10532};
10533
10534static struct hda_input_mux alc262_hp_rp5700_capture_source = {
10535 .num_items = 1,
10536 .items = {
10537 { "Line", 0x1 },
10538 },
10539};
10540
Takashi Iwai42171c12009-05-08 14:11:43 +020010541/* bind hp and internal speaker mute (with plug check) as master switch */
10542static void alc262_hippo_master_update(struct hda_codec *codec)
10543{
10544 struct alc_spec *spec = codec->spec;
10545 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
10546 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
10547 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
10548 unsigned int mute;
10549
10550 /* HP */
10551 mute = spec->master_sw ? 0 : HDA_AMP_MUTE;
10552 snd_hda_codec_amp_stereo(codec, hp_nid, HDA_OUTPUT, 0,
10553 HDA_AMP_MUTE, mute);
10554 /* mute internal speaker per jack sense */
10555 if (spec->jack_present)
10556 mute = HDA_AMP_MUTE;
10557 if (line_nid)
10558 snd_hda_codec_amp_stereo(codec, line_nid, HDA_OUTPUT, 0,
10559 HDA_AMP_MUTE, mute);
10560 if (speaker_nid && speaker_nid != line_nid)
10561 snd_hda_codec_amp_stereo(codec, speaker_nid, HDA_OUTPUT, 0,
10562 HDA_AMP_MUTE, mute);
10563}
10564
10565#define alc262_hippo_master_sw_get alc262_hp_master_sw_get
10566
10567static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol,
10568 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai0724ea22007-08-23 00:31:43 +020010569{
10570 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Takashi Iwai42171c12009-05-08 14:11:43 +020010571 struct alc_spec *spec = codec->spec;
10572 int val = !!*ucontrol->value.integer.value;
Takashi Iwai0724ea22007-08-23 00:31:43 +020010573
Takashi Iwai42171c12009-05-08 14:11:43 +020010574 if (val == spec->master_sw)
10575 return 0;
10576 spec->master_sw = val;
10577 alc262_hippo_master_update(codec);
10578 return 1;
Takashi Iwai0724ea22007-08-23 00:31:43 +020010579}
Takashi Iwai5b319542007-07-26 11:49:22 +020010580
Takashi Iwai42171c12009-05-08 14:11:43 +020010581#define ALC262_HIPPO_MASTER_SWITCH \
10582 { \
10583 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
10584 .name = "Master Playback Switch", \
10585 .info = snd_ctl_boolean_mono_info, \
10586 .get = alc262_hippo_master_sw_get, \
10587 .put = alc262_hippo_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010010588 }, \
10589 { \
10590 .iface = NID_MAPPING, \
10591 .name = "Master Playback Switch", \
10592 .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \
10593 (SUBDEV_SPEAKER(0) << 16), \
Takashi Iwai42171c12009-05-08 14:11:43 +020010594 }
10595
10596static struct snd_kcontrol_new alc262_hippo_mixer[] = {
10597 ALC262_HIPPO_MASTER_SWITCH,
10598 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10599 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10600 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
10601 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10602 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10603 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10604 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10605 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10606 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10607 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10608 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
10609 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
10610 { } /* end */
10611};
10612
10613static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
10614 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10615 ALC262_HIPPO_MASTER_SWITCH,
10616 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10617 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
10618 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10619 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10620 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10621 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10622 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10623 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10624 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10625 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
10626 { } /* end */
10627};
10628
10629/* mute/unmute internal speaker according to the hp jack and mute state */
10630static void alc262_hippo_automute(struct hda_codec *codec)
10631{
10632 struct alc_spec *spec = codec->spec;
10633 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
Takashi Iwai42171c12009-05-08 14:11:43 +020010634
Wu Fengguang864f92b2009-11-18 12:38:02 +080010635 spec->jack_present = snd_hda_jack_detect(codec, hp_nid);
Takashi Iwai42171c12009-05-08 14:11:43 +020010636 alc262_hippo_master_update(codec);
10637}
10638
10639static void alc262_hippo_unsol_event(struct hda_codec *codec, unsigned int res)
10640{
10641 if ((res >> 26) != ALC880_HP_EVENT)
10642 return;
10643 alc262_hippo_automute(codec);
10644}
10645
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010646static void alc262_hippo_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020010647{
10648 struct alc_spec *spec = codec->spec;
10649
10650 spec->autocfg.hp_pins[0] = 0x15;
10651 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai42171c12009-05-08 14:11:43 +020010652}
10653
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010654static void alc262_hippo1_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020010655{
10656 struct alc_spec *spec = codec->spec;
10657
10658 spec->autocfg.hp_pins[0] = 0x1b;
10659 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai42171c12009-05-08 14:11:43 +020010660}
10661
10662
Kailang Yang272a5272007-05-14 11:00:38 +020010663static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +020010664 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020010665 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang272a5272007-05-14 11:00:38 +020010666 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10667 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10668 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10669 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10670 { } /* end */
10671};
10672
Kailang Yang83c34212007-07-05 11:43:05 +020010673static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020010674 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10675 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang83c34212007-07-05 11:43:05 +020010676 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10677 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10678 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10679 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10680 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10681 { } /* end */
10682};
Kailang Yang272a5272007-05-14 11:00:38 +020010683
Tony Vroonba340e82009-02-02 19:01:30 +000010684static struct snd_kcontrol_new alc262_tyan_mixer[] = {
10685 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10686 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
10687 HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
10688 HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT),
10689 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10690 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10691 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10692 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10693 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10694 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10695 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10696 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
10697 { } /* end */
10698};
10699
10700static struct hda_verb alc262_tyan_verbs[] = {
10701 /* Headphone automute */
10702 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10703 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10704 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10705
10706 /* P11 AUX_IN, white 4-pin connector */
10707 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10708 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
10709 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
10710 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
10711
10712 {}
10713};
10714
10715/* unsolicited event for HP jack sensing */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010716static void alc262_tyan_setup(struct hda_codec *codec)
Tony Vroonba340e82009-02-02 19:01:30 +000010717{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010718 struct alc_spec *spec = codec->spec;
Tony Vroonba340e82009-02-02 19:01:30 +000010719
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010720 spec->autocfg.hp_pins[0] = 0x1b;
10721 spec->autocfg.speaker_pins[0] = 0x15;
Tony Vroonba340e82009-02-02 19:01:30 +000010722}
10723
Tony Vroonba340e82009-02-02 19:01:30 +000010724
Kailang Yangdf694da2005-12-05 19:42:22 +010010725#define alc262_capture_mixer alc882_capture_mixer
10726#define alc262_capture_alt_mixer alc882_capture_alt_mixer
10727
10728/*
10729 * generic initialization of ADC, input mixers and output mixers
10730 */
10731static struct hda_verb alc262_init_verbs[] = {
10732 /*
10733 * Unmute ADC0-2 and set the default input to mic-in
10734 */
10735 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
10736 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10737 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10738 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10739 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
10740 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10741
Takashi Iwaicb53c622007-08-10 17:21:45 +020010742 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010010743 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010744 * Note: PASD motherboards uses the Line In 2 as the input for
10745 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010010746 */
10747 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010748 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10749 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10750 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10751 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10752 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010010753
10754 /*
10755 * Set up output mixers (0x0c - 0x0e)
10756 */
10757 /* set vol=0 to output mixers */
10758 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10759 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10760 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10761 /* set up input amps for analog loopback */
10762 /* Amp Indices: DAC = 0, mixer = 1 */
10763 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10764 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10765 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10766 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10767 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10768 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10769
10770 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
10771 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
10772 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
10773 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10774 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10775 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10776
10777 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
10778 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
10779 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
10780 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
10781 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Kailang Yangea1fb292008-08-26 12:58:38 +020010782
Kailang Yangdf694da2005-12-05 19:42:22 +010010783 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
10784 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Kailang Yangea1fb292008-08-26 12:58:38 +020010785
Kailang Yangdf694da2005-12-05 19:42:22 +010010786 /* FIXME: use matrix-type input source selection */
10787 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10788 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10789 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10790 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10791 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10792 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10793 /* Input mixer2 */
10794 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10795 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10796 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10797 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10798 /* Input mixer3 */
10799 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10800 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10801 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010802 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +010010803
10804 { }
10805};
10806
Kailang Yang4e555fe2008-08-26 13:05:55 +020010807static struct hda_verb alc262_eapd_verbs[] = {
10808 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
10809 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
10810 { }
10811};
10812
Kailang Yangccc656c2006-10-17 12:32:26 +020010813static struct hda_verb alc262_hippo1_unsol_verbs[] = {
10814 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
10815 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
10816 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
10817
10818 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10819 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10820 {}
10821};
10822
Kailang Yang272a5272007-05-14 11:00:38 +020010823static struct hda_verb alc262_sony_unsol_verbs[] = {
10824 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
10825 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10826 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
10827
10828 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10829 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +090010830 {}
Kailang Yang272a5272007-05-14 11:00:38 +020010831};
10832
Kailang Yang4e555fe2008-08-26 13:05:55 +020010833static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
10834 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10835 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10836 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10837 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10838 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang4e555fe2008-08-26 13:05:55 +020010839 { } /* end */
10840};
10841
10842static struct hda_verb alc262_toshiba_s06_verbs[] = {
10843 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10844 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10845 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10846 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10847 {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
10848 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10849 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
10850 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10851 {}
10852};
10853
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010854static void alc262_toshiba_s06_setup(struct hda_codec *codec)
Kailang Yang4e555fe2008-08-26 13:05:55 +020010855{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010856 struct alc_spec *spec = codec->spec;
10857
10858 spec->autocfg.hp_pins[0] = 0x15;
10859 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010860 spec->ext_mic.pin = 0x18;
10861 spec->ext_mic.mux_idx = 0;
10862 spec->int_mic.pin = 0x12;
10863 spec->int_mic.mux_idx = 9;
10864 spec->auto_mic = 1;
Kailang Yang4e555fe2008-08-26 13:05:55 +020010865}
10866
Takashi Iwai834be882006-03-01 14:16:17 +010010867/*
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010868 * nec model
10869 * 0x15 = headphone
10870 * 0x16 = internal speaker
10871 * 0x18 = external mic
10872 */
10873
10874static struct snd_kcontrol_new alc262_nec_mixer[] = {
10875 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
10876 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
10877
10878 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10879 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10880 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10881
10882 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
10883 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10884 { } /* end */
10885};
10886
10887static struct hda_verb alc262_nec_verbs[] = {
10888 /* Unmute Speaker */
10889 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10890
10891 /* Headphone */
10892 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10893 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10894
10895 /* External mic to headphone */
10896 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10897 /* External mic to speaker */
10898 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10899 {}
10900};
10901
10902/*
Takashi Iwai834be882006-03-01 14:16:17 +010010903 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +010010904 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
10905 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +010010906 */
10907
10908#define ALC_HP_EVENT 0x37
10909
10910static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
10911 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
10912 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +010010913 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
10914 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +010010915 {}
10916};
10917
Jiang zhe0e31daf2008-03-20 12:12:39 +010010918static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
10919 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
10920 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10921 {}
10922};
10923
Daniel T Chene2595322009-12-19 18:19:02 -050010924static struct hda_verb alc262_lenovo_3000_init_verbs[] = {
10925 /* Front Mic pin: input vref at 50% */
10926 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
10927 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10928 {}
10929};
10930
Takashi Iwai834be882006-03-01 14:16:17 +010010931static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +020010932 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +010010933 .items = {
10934 { "Mic", 0x0 },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020010935 { "Int Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +010010936 { "CD", 0x4 },
10937 },
10938};
10939
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010940static struct hda_input_mux alc262_HP_capture_source = {
10941 .num_items = 5,
10942 .items = {
10943 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +020010944 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010945 { "Line", 0x2 },
10946 { "CD", 0x4 },
10947 { "AUX IN", 0x6 },
10948 },
10949};
10950
zhejiangaccbe492007-08-31 12:36:05 +020010951static struct hda_input_mux alc262_HP_D7000_capture_source = {
10952 .num_items = 4,
10953 .items = {
10954 { "Mic", 0x0 },
10955 { "Front Mic", 0x2 },
10956 { "Line", 0x1 },
10957 { "CD", 0x4 },
10958 },
10959};
10960
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010961/* mute/unmute internal speaker according to the hp jacks and mute state */
Takashi Iwai834be882006-03-01 14:16:17 +010010962static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
10963{
10964 struct alc_spec *spec = codec->spec;
10965 unsigned int mute;
10966
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010967 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080010968 spec->jack_present = snd_hda_jack_detect(codec, 0x14) ||
10969 snd_hda_jack_detect(codec, 0x1b);
Takashi Iwai834be882006-03-01 14:16:17 +010010970 spec->sense_updated = 1;
10971 }
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010972 /* unmute internal speaker only if both HPs are unplugged and
10973 * master switch is on
10974 */
10975 if (spec->jack_present)
10976 mute = HDA_AMP_MUTE;
10977 else
Takashi Iwai834be882006-03-01 14:16:17 +010010978 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010979 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
10980 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +010010981}
10982
10983/* unsolicited event for HP jack sensing */
10984static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
10985 unsigned int res)
10986{
10987 if ((res >> 26) != ALC_HP_EVENT)
10988 return;
10989 alc262_fujitsu_automute(codec, 1);
10990}
10991
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010992static void alc262_fujitsu_init_hook(struct hda_codec *codec)
10993{
10994 alc262_fujitsu_automute(codec, 1);
10995}
10996
Takashi Iwai834be882006-03-01 14:16:17 +010010997/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +020010998static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
10999 .ops = &snd_hda_bind_vol,
11000 .values = {
11001 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
11002 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
11003 0
11004 },
11005};
Takashi Iwai834be882006-03-01 14:16:17 +010011006
Jiang zhe0e31daf2008-03-20 12:12:39 +010011007/* mute/unmute internal speaker according to the hp jack and mute state */
11008static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
11009{
11010 struct alc_spec *spec = codec->spec;
11011 unsigned int mute;
11012
11013 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011014 spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
Jiang zhe0e31daf2008-03-20 12:12:39 +010011015 spec->sense_updated = 1;
11016 }
11017 if (spec->jack_present) {
11018 /* mute internal speaker */
11019 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11020 HDA_AMP_MUTE, HDA_AMP_MUTE);
11021 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
11022 HDA_AMP_MUTE, HDA_AMP_MUTE);
11023 } else {
11024 /* unmute internal speaker if necessary */
11025 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
11026 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11027 HDA_AMP_MUTE, mute);
11028 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
11029 HDA_AMP_MUTE, mute);
11030 }
11031}
11032
11033/* unsolicited event for HP jack sensing */
11034static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
11035 unsigned int res)
11036{
11037 if ((res >> 26) != ALC_HP_EVENT)
11038 return;
11039 alc262_lenovo_3000_automute(codec, 1);
11040}
11041
Takashi Iwai8de56b72009-07-24 16:51:47 +020011042static int amp_stereo_mute_update(struct hda_codec *codec, hda_nid_t nid,
11043 int dir, int idx, long *valp)
11044{
11045 int i, change = 0;
11046
11047 for (i = 0; i < 2; i++, valp++)
11048 change |= snd_hda_codec_amp_update(codec, nid, i, dir, idx,
11049 HDA_AMP_MUTE,
11050 *valp ? 0 : HDA_AMP_MUTE);
11051 return change;
11052}
11053
Takashi Iwai834be882006-03-01 14:16:17 +010011054/* bind hp and internal speaker mute (with plug check) */
11055static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
11056 struct snd_ctl_elem_value *ucontrol)
11057{
11058 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11059 long *valp = ucontrol->value.integer.value;
11060 int change;
11061
Takashi Iwai8de56b72009-07-24 16:51:47 +020011062 change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
11063 change |= amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
Takashi Iwai82beb8f2007-08-10 17:09:26 +020011064 if (change)
11065 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +010011066 return change;
11067}
11068
11069static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +020011070 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +010011071 {
11072 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11073 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010011074 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwai834be882006-03-01 14:16:17 +010011075 .info = snd_hda_mixer_amp_switch_info,
11076 .get = snd_hda_mixer_amp_switch_get,
11077 .put = alc262_fujitsu_master_sw_put,
11078 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11079 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011080 {
11081 .iface = NID_MAPPING,
11082 .name = "Master Playback Switch",
11083 .private_value = 0x1b,
11084 },
Takashi Iwai834be882006-03-01 14:16:17 +010011085 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11086 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11087 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11088 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11089 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011090 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
11091 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11092 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010011093 { } /* end */
11094};
11095
Jiang zhe0e31daf2008-03-20 12:12:39 +010011096/* bind hp and internal speaker mute (with plug check) */
11097static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
11098 struct snd_ctl_elem_value *ucontrol)
11099{
11100 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11101 long *valp = ucontrol->value.integer.value;
11102 int change;
11103
Takashi Iwai8de56b72009-07-24 16:51:47 +020011104 change = amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
Jiang zhe0e31daf2008-03-20 12:12:39 +010011105 if (change)
11106 alc262_lenovo_3000_automute(codec, 0);
11107 return change;
11108}
11109
11110static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
11111 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
11112 {
11113 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11114 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010011115 .subdevice = HDA_SUBDEV_AMP_FLAG,
Jiang zhe0e31daf2008-03-20 12:12:39 +010011116 .info = snd_hda_mixer_amp_switch_info,
11117 .get = snd_hda_mixer_amp_switch_get,
11118 .put = alc262_lenovo_3000_master_sw_put,
11119 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
11120 },
11121 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11122 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11123 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11124 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11125 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11126 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
11127 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11128 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
11129 { } /* end */
11130};
11131
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011132static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
11133 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai42171c12009-05-08 14:11:43 +020011134 ALC262_HIPPO_MASTER_SWITCH,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011135 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11136 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11137 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11138 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11139 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11140 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11141 { } /* end */
11142};
11143
Takashi Iwai304dcaa2006-07-25 14:51:16 +020011144/* additional init verbs for Benq laptops */
11145static struct hda_verb alc262_EAPD_verbs[] = {
11146 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
11147 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
11148 {}
11149};
11150
Kailang Yang83c34212007-07-05 11:43:05 +020011151static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
11152 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11153 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11154
11155 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
11156 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
11157 {}
11158};
11159
Tobin Davisf651b502007-10-26 12:40:47 +020011160/* Samsung Q1 Ultra Vista model setup */
11161static struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011162 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11163 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020011164 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11165 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11166 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011167 HDA_CODEC_VOLUME("Headphone Mic Boost", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020011168 { } /* end */
11169};
11170
11171static struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011172 /* output mixer */
11173 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11174 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11175 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11176 /* speaker */
11177 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11178 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11179 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11180 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11181 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +020011182 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011183 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11184 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11185 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11186 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11187 /* internal mic */
11188 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11189 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11190 /* ADC, choose mic */
11191 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11192 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11193 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11194 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11195 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11196 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11197 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
11198 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
11199 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
11200 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +020011201 {}
11202};
11203
Tobin Davisf651b502007-10-26 12:40:47 +020011204/* mute/unmute internal speaker according to the hp jack and mute state */
11205static void alc262_ultra_automute(struct hda_codec *codec)
11206{
11207 struct alc_spec *spec = codec->spec;
11208 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +020011209
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011210 mute = 0;
11211 /* auto-mute only when HP is used as HP */
11212 if (!spec->cur_mux[0]) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011213 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011214 if (spec->jack_present)
11215 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +020011216 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011217 /* mute/unmute internal speaker */
11218 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11219 HDA_AMP_MUTE, mute);
11220 /* mute/unmute HP */
11221 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
11222 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +020011223}
11224
11225/* unsolicited event for HP jack sensing */
11226static void alc262_ultra_unsol_event(struct hda_codec *codec,
11227 unsigned int res)
11228{
11229 if ((res >> 26) != ALC880_HP_EVENT)
11230 return;
11231 alc262_ultra_automute(codec);
11232}
11233
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011234static struct hda_input_mux alc262_ultra_capture_source = {
11235 .num_items = 2,
11236 .items = {
11237 { "Mic", 0x1 },
11238 { "Headphone", 0x7 },
11239 },
11240};
11241
11242static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
11243 struct snd_ctl_elem_value *ucontrol)
11244{
11245 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11246 struct alc_spec *spec = codec->spec;
11247 int ret;
11248
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011249 ret = alc_mux_enum_put(kcontrol, ucontrol);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011250 if (!ret)
11251 return 0;
11252 /* reprogram the HP pin as mic or HP according to the input source */
11253 snd_hda_codec_write_cache(codec, 0x15, 0,
11254 AC_VERB_SET_PIN_WIDGET_CONTROL,
11255 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
11256 alc262_ultra_automute(codec); /* mute/unmute HP */
11257 return ret;
11258}
11259
11260static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
11261 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
11262 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
11263 {
11264 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11265 .name = "Capture Source",
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011266 .info = alc_mux_enum_info,
11267 .get = alc_mux_enum_get,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011268 .put = alc262_ultra_mux_enum_put,
11269 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011270 {
11271 .iface = NID_MAPPING,
11272 .name = "Capture Source",
11273 .private_value = 0x15,
11274 },
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011275 { } /* end */
11276};
11277
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011278/* We use two mixers depending on the output pin; 0x16 is a mono output
11279 * and thus it's bound with a different mixer.
11280 * This function returns which mixer amp should be used.
11281 */
11282static int alc262_check_volbit(hda_nid_t nid)
11283{
11284 if (!nid)
11285 return 0;
11286 else if (nid == 0x16)
11287 return 2;
11288 else
11289 return 1;
11290}
11291
11292static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
11293 const char *pfx, int *vbits)
11294{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011295 unsigned long val;
11296 int vbit;
11297
11298 vbit = alc262_check_volbit(nid);
11299 if (!vbit)
11300 return 0;
11301 if (*vbits & vbit) /* a volume control for this mixer already there */
11302 return 0;
11303 *vbits |= vbit;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011304 if (vbit == 2)
11305 val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT);
11306 else
11307 val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT);
Takashi Iwai0afe5f82009-10-02 09:20:00 +020011308 return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011309}
11310
11311static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
11312 const char *pfx)
11313{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011314 unsigned long val;
11315
11316 if (!nid)
11317 return 0;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011318 if (nid == 0x16)
11319 val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
11320 else
11321 val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
Takashi Iwai0afe5f82009-10-02 09:20:00 +020011322 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011323}
11324
Kailang Yangdf694da2005-12-05 19:42:22 +010011325/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011326static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
11327 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010011328{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011329 const char *pfx;
11330 int vbits;
Kailang Yangdf694da2005-12-05 19:42:22 +010011331 int err;
11332
11333 spec->multiout.num_dacs = 1; /* only use one dac */
11334 spec->multiout.dac_nids = spec->private_dac_nids;
11335 spec->multiout.dac_nids[0] = 2;
11336
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011337 if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
11338 pfx = "Master";
11339 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
11340 pfx = "Speaker";
11341 else
11342 pfx = "Front";
11343 err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[0], pfx);
11344 if (err < 0)
11345 return err;
11346 err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[0], "Speaker");
11347 if (err < 0)
11348 return err;
11349 err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[0], "Headphone");
11350 if (err < 0)
11351 return err;
Kailang Yangdf694da2005-12-05 19:42:22 +010011352
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011353 vbits = alc262_check_volbit(cfg->line_out_pins[0]) |
11354 alc262_check_volbit(cfg->speaker_pins[0]) |
11355 alc262_check_volbit(cfg->hp_pins[0]);
11356 if (vbits == 1 || vbits == 2)
11357 pfx = "Master"; /* only one mixer is used */
11358 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
11359 pfx = "Speaker";
11360 else
11361 pfx = "Front";
11362 vbits = 0;
11363 err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[0], pfx, &vbits);
11364 if (err < 0)
11365 return err;
11366 err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[0], "Speaker",
11367 &vbits);
11368 if (err < 0)
11369 return err;
11370 err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[0], "Headphone",
11371 &vbits);
11372 if (err < 0)
11373 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011374 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +010011375}
11376
Takashi Iwai05f5f472009-08-25 13:10:18 +020011377#define alc262_auto_create_input_ctls \
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +010011378 alc882_auto_create_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +010011379
11380/*
11381 * generic initialization of ADC, input mixers and output mixers
11382 */
11383static struct hda_verb alc262_volume_init_verbs[] = {
11384 /*
11385 * Unmute ADC0-2 and set the default input to mic-in
11386 */
11387 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11388 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11389 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11390 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11391 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11392 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11393
Takashi Iwaicb53c622007-08-10 17:21:45 +020011394 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010011395 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011396 * Note: PASD motherboards uses the Line In 2 as the input for
11397 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010011398 */
11399 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011400 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11401 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11402 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11403 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11404 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011405
11406 /*
11407 * Set up output mixers (0x0c - 0x0f)
11408 */
11409 /* set vol=0 to output mixers */
11410 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11411 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11412 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yangea1fb292008-08-26 12:58:38 +020011413
Kailang Yangdf694da2005-12-05 19:42:22 +010011414 /* set up input amps for analog loopback */
11415 /* Amp Indices: DAC = 0, mixer = 1 */
11416 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11417 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11418 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11419 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11420 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11421 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11422
11423 /* FIXME: use matrix-type input source selection */
11424 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
11425 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
11426 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11427 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11428 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11429 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11430 /* Input mixer2 */
11431 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11432 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11433 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11434 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11435 /* Input mixer3 */
11436 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11437 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11438 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11439 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11440
11441 { }
11442};
11443
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011444static struct hda_verb alc262_HP_BPC_init_verbs[] = {
11445 /*
11446 * Unmute ADC0-2 and set the default input to mic-in
11447 */
11448 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11449 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11450 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11451 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11452 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11453 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11454
Takashi Iwaicb53c622007-08-10 17:21:45 +020011455 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011456 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011457 * Note: PASD motherboards uses the Line In 2 as the input for
11458 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011459 */
11460 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011461 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11462 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11463 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11464 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11465 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11466 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
11467 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Kailang Yangea1fb292008-08-26 12:58:38 +020011468
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011469 /*
11470 * Set up output mixers (0x0c - 0x0e)
11471 */
11472 /* set vol=0 to output mixers */
11473 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11474 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11475 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11476
11477 /* set up input amps for analog loopback */
11478 /* Amp Indices: DAC = 0, mixer = 1 */
11479 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11480 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11481 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11482 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11483 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11484 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11485
Takashi Iwaice875f02008-01-28 18:17:43 +010011486 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011487 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11488 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11489
11490 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
11491 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
11492
11493 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11494 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11495
11496 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11497 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11498 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11499 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11500 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11501
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020011502 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011503 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
11504 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020011505 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011506 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
11507 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
11508
11509
11510 /* FIXME: use matrix-type input source selection */
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020011511 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */
11512 /* Input mixer1: only unmute Mic */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011513 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020011514 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
11515 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11516 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11517 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11518 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
11519 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
11520 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
11521 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011522 /* Input mixer2 */
11523 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020011524 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
11525 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11526 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11527 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11528 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
11529 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
11530 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
11531 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011532 /* Input mixer3 */
11533 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020011534 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
11535 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11536 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11537 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11538 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
11539 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
11540 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
11541 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011542
Takashi Iwaice875f02008-01-28 18:17:43 +010011543 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11544
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011545 { }
11546};
11547
Kailang Yangcd7509a2007-01-26 18:33:17 +010011548static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
11549 /*
11550 * Unmute ADC0-2 and set the default input to mic-in
11551 */
11552 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11553 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11554 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11555 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11556 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11557 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11558
Takashi Iwaicb53c622007-08-10 17:21:45 +020011559 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +010011560 * mixer widget
11561 * Note: PASD motherboards uses the Line In 2 as the input for front
11562 * panel mic (mic 2)
11563 */
11564 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011565 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11566 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11567 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11568 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11569 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11570 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
11571 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
11572 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +010011573 /*
11574 * Set up output mixers (0x0c - 0x0e)
11575 */
11576 /* set vol=0 to output mixers */
11577 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11578 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11579 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11580
11581 /* set up input amps for analog loopback */
11582 /* Amp Indices: DAC = 0, mixer = 1 */
11583 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11584 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11585 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11586 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11587 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11588 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11589
11590
11591 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
11592 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
11593 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
11594 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
11595 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
11596 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
11597 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
11598
11599 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
11600 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
11601
11602 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11603 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
11604
11605 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
11606 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
11607 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
11608 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
11609 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
11610 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
11611
11612 /* FIXME: use matrix-type input source selection */
11613 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
11614 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
11615 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
11616 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
11617 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
11618 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
11619 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
11620 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
11621 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
11622 /* Input mixer2 */
11623 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11624 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11625 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
11626 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
11627 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
11628 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
11629 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
11630 /* Input mixer3 */
11631 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11632 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11633 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
11634 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
11635 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
11636 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
11637 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
11638
Takashi Iwaice875f02008-01-28 18:17:43 +010011639 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11640
Kailang Yangcd7509a2007-01-26 18:33:17 +010011641 { }
11642};
11643
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011644static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
11645
11646 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */
11647 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
11648 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
11649
11650 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */
11651 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
11652 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
11653 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
11654
11655 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */
11656 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11657 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11658 {}
11659};
11660
11661
Takashi Iwaicb53c622007-08-10 17:21:45 +020011662#ifdef CONFIG_SND_HDA_POWER_SAVE
11663#define alc262_loopbacks alc880_loopbacks
11664#endif
11665
Sasha Alexandrdef319f2009-06-16 16:00:15 -040011666/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010011667#define alc262_pcm_analog_playback alc880_pcm_analog_playback
11668#define alc262_pcm_analog_capture alc880_pcm_analog_capture
11669#define alc262_pcm_digital_playback alc880_pcm_digital_playback
11670#define alc262_pcm_digital_capture alc880_pcm_digital_capture
11671
11672/*
11673 * BIOS auto configuration
11674 */
11675static int alc262_parse_auto_config(struct hda_codec *codec)
11676{
11677 struct alc_spec *spec = codec->spec;
11678 int err;
11679 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
11680
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011681 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
11682 alc262_ignore);
11683 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011684 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +010011685 if (!spec->autocfg.line_outs) {
Takashi Iwai0852d7a2009-02-11 11:35:15 +010011686 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
Takashi Iwaie64f14f2009-01-20 18:32:55 +010011687 spec->multiout.max_channels = 2;
11688 spec->no_analog = 1;
11689 goto dig_only;
11690 }
Kailang Yangdf694da2005-12-05 19:42:22 +010011691 return 0; /* can't find valid BIOS pin config */
Takashi Iwaie64f14f2009-01-20 18:32:55 +010011692 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011693 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
11694 if (err < 0)
11695 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020011696 err = alc262_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011697 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011698 return err;
11699
11700 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
11701
Takashi Iwaie64f14f2009-01-20 18:32:55 +010011702 dig_only:
Takashi Iwai0852d7a2009-02-11 11:35:15 +010011703 if (spec->autocfg.dig_outs) {
Kailang Yangdf694da2005-12-05 19:42:22 +010011704 spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
Takashi Iwai0852d7a2009-02-11 11:35:15 +010011705 spec->dig_out_type = spec->autocfg.dig_out_type[0];
Takashi Iwaie64f14f2009-01-20 18:32:55 +010011706 }
Kailang Yangdf694da2005-12-05 19:42:22 +010011707 if (spec->autocfg.dig_in_pin)
11708 spec->dig_in_nid = ALC262_DIGIN_NID;
11709
Takashi Iwai603c4012008-07-30 15:01:44 +020011710 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010011711 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010011712
Takashi Iwaid88897e2008-10-31 15:01:37 +010011713 add_verb(spec, alc262_volume_init_verbs);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020011714 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020011715 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010011716
Takashi Iwai776e1842007-08-29 15:07:11 +020011717 err = alc_auto_add_mic_boost(codec);
11718 if (err < 0)
11719 return err;
11720
Takashi Iwai4a79ba32009-04-22 16:31:35 +020011721 alc_ssid_check(codec, 0x15, 0x14, 0x1b);
11722
Kailang Yangdf694da2005-12-05 19:42:22 +010011723 return 1;
11724}
11725
11726#define alc262_auto_init_multi_out alc882_auto_init_multi_out
11727#define alc262_auto_init_hp_out alc882_auto_init_hp_out
11728#define alc262_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaif511b012008-08-15 16:46:42 +020011729#define alc262_auto_init_input_src alc882_auto_init_input_src
Kailang Yangdf694da2005-12-05 19:42:22 +010011730
11731
11732/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +010011733static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010011734{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011735 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010011736 alc262_auto_init_multi_out(codec);
11737 alc262_auto_init_hp_out(codec);
11738 alc262_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020011739 alc262_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011740 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020011741 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010011742}
11743
11744/*
11745 * configuration and preset
11746 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011747static const char *alc262_models[ALC262_MODEL_LAST] = {
11748 [ALC262_BASIC] = "basic",
11749 [ALC262_HIPPO] = "hippo",
11750 [ALC262_HIPPO_1] = "hippo_1",
11751 [ALC262_FUJITSU] = "fujitsu",
11752 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +010011753 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +010011754 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +010011755 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011756 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +020011757 [ALC262_BENQ_T31] = "benq-t31",
11758 [ALC262_SONY_ASSAMD] = "sony-assamd",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020011759 [ALC262_TOSHIBA_S06] = "toshiba-s06",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011760 [ALC262_TOSHIBA_RX1] = "toshiba-rx1",
Tobin Davisf651b502007-10-26 12:40:47 +020011761 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +010011762 [ALC262_LENOVO_3000] = "lenovo-3000",
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011763 [ALC262_NEC] = "nec",
Tony Vroonba340e82009-02-02 19:01:30 +000011764 [ALC262_TYAN] = "tyan",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011765 [ALC262_AUTO] = "auto",
11766};
11767
11768static struct snd_pci_quirk alc262_cfg_tbl[] = {
11769 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011770 SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
Takashi Iwaidea0a502009-02-09 17:14:52 +010011771 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
11772 ALC262_HP_BPC),
11773 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series",
11774 ALC262_HP_BPC),
Takashi Iwai53eff7e2009-02-27 17:49:44 +010011775 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
11776 ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011777 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011778 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011779 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011780 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011781 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011782 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011783 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011784 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011785 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
11786 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
11787 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011788 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
11789 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +010011790 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011791 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011792 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011793 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaibd6afe32009-03-04 11:30:25 +010011794 SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */
Takashi Iwai376b5082009-06-22 11:03:13 +020011795 SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06),
Daniel T Chen95491d92009-11-08 19:03:55 -050011796 SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO),
Takashi Iwai12929ba2009-11-17 15:58:35 +010011797 SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO),
Takashi Iwaic5b51652009-11-17 16:01:58 +010011798#if 0 /* disable the quirk since model=auto works better in recent versions */
Takashi Iwaif872a912009-02-26 00:57:01 +010011799 SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
11800 ALC262_SONY_ASSAMD),
Takashi Iwaic5b51652009-11-17 16:01:58 +010011801#endif
Akio Idehara36ca6e12008-06-09 22:57:40 +090011802 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011803 ALC262_TOSHIBA_RX1),
Kailang Yang80ffe862008-10-15 11:23:27 +020011804 SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011805 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +010011806 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Tony Vroonba340e82009-02-02 19:01:30 +000011807 SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
Takashi Iwaidea0a502009-02-09 17:14:52 +010011808 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1",
11809 ALC262_ULTRA),
Luke Yelavich3e420e72008-12-16 12:37:47 +110011810 SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
Jiang zhe0e31daf2008-03-20 12:12:39 +010011811 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011812 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +020011813 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011814 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +010011815 {}
11816};
11817
11818static struct alc_config_preset alc262_presets[] = {
11819 [ALC262_BASIC] = {
11820 .mixers = { alc262_base_mixer },
11821 .init_verbs = { alc262_init_verbs },
11822 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11823 .dac_nids = alc262_dac_nids,
11824 .hp_nid = 0x03,
11825 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11826 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +010011827 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +010011828 },
Kailang Yangccc656c2006-10-17 12:32:26 +020011829 [ALC262_HIPPO] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011830 .mixers = { alc262_hippo_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020011831 .init_verbs = { alc262_init_verbs, alc_hp15_unsol_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020011832 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11833 .dac_nids = alc262_dac_nids,
11834 .hp_nid = 0x03,
11835 .dig_out_nid = ALC262_DIGOUT_NID,
11836 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11837 .channel_mode = alc262_modes,
11838 .input_mux = &alc262_capture_source,
11839 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011840 .setup = alc262_hippo_setup,
11841 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020011842 },
11843 [ALC262_HIPPO_1] = {
11844 .mixers = { alc262_hippo1_mixer },
11845 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
11846 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11847 .dac_nids = alc262_dac_nids,
11848 .hp_nid = 0x02,
11849 .dig_out_nid = ALC262_DIGOUT_NID,
11850 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11851 .channel_mode = alc262_modes,
11852 .input_mux = &alc262_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020011853 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011854 .setup = alc262_hippo1_setup,
11855 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020011856 },
Takashi Iwai834be882006-03-01 14:16:17 +010011857 [ALC262_FUJITSU] = {
11858 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011859 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
11860 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +010011861 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11862 .dac_nids = alc262_dac_nids,
11863 .hp_nid = 0x03,
11864 .dig_out_nid = ALC262_DIGOUT_NID,
11865 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11866 .channel_mode = alc262_modes,
11867 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010011868 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011869 .init_hook = alc262_fujitsu_init_hook,
Takashi Iwai834be882006-03-01 14:16:17 +010011870 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011871 [ALC262_HP_BPC] = {
11872 .mixers = { alc262_HP_BPC_mixer },
11873 .init_verbs = { alc262_HP_BPC_init_verbs },
11874 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11875 .dac_nids = alc262_dac_nids,
11876 .hp_nid = 0x03,
11877 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11878 .channel_mode = alc262_modes,
11879 .input_mux = &alc262_HP_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010011880 .unsol_event = alc262_hp_bpc_unsol_event,
11881 .init_hook = alc262_hp_bpc_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011882 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010011883 [ALC262_HP_BPC_D7000_WF] = {
11884 .mixers = { alc262_HP_BPC_WildWest_mixer },
11885 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
11886 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11887 .dac_nids = alc262_dac_nids,
11888 .hp_nid = 0x03,
11889 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11890 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020011891 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010011892 .unsol_event = alc262_hp_wildwest_unsol_event,
11893 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011894 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010011895 [ALC262_HP_BPC_D7000_WL] = {
11896 .mixers = { alc262_HP_BPC_WildWest_mixer,
11897 alc262_HP_BPC_WildWest_option_mixer },
11898 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
11899 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11900 .dac_nids = alc262_dac_nids,
11901 .hp_nid = 0x03,
11902 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11903 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020011904 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010011905 .unsol_event = alc262_hp_wildwest_unsol_event,
11906 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011907 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011908 [ALC262_HP_TC_T5735] = {
11909 .mixers = { alc262_hp_t5735_mixer },
11910 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
11911 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11912 .dac_nids = alc262_dac_nids,
11913 .hp_nid = 0x03,
11914 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11915 .channel_mode = alc262_modes,
11916 .input_mux = &alc262_capture_source,
Takashi Iwaidc99be42010-01-20 08:35:06 +010011917 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011918 .setup = alc262_hp_t5735_setup,
Takashi Iwaidc99be42010-01-20 08:35:06 +010011919 .init_hook = alc_inithook,
Kailang Yang8c427222008-01-10 13:03:59 +010011920 },
11921 [ALC262_HP_RP5700] = {
11922 .mixers = { alc262_hp_rp5700_mixer },
11923 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
11924 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11925 .dac_nids = alc262_dac_nids,
11926 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11927 .channel_mode = alc262_modes,
11928 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011929 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +020011930 [ALC262_BENQ_ED8] = {
11931 .mixers = { alc262_base_mixer },
11932 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
11933 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11934 .dac_nids = alc262_dac_nids,
11935 .hp_nid = 0x03,
11936 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11937 .channel_mode = alc262_modes,
11938 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011939 },
Kailang Yang272a5272007-05-14 11:00:38 +020011940 [ALC262_SONY_ASSAMD] = {
11941 .mixers = { alc262_sony_mixer },
11942 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
11943 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11944 .dac_nids = alc262_dac_nids,
11945 .hp_nid = 0x02,
11946 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11947 .channel_mode = alc262_modes,
11948 .input_mux = &alc262_capture_source,
11949 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011950 .setup = alc262_hippo_setup,
11951 .init_hook = alc262_hippo_automute,
Kailang Yang83c34212007-07-05 11:43:05 +020011952 },
11953 [ALC262_BENQ_T31] = {
11954 .mixers = { alc262_benq_t31_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020011955 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs,
11956 alc_hp15_unsol_verbs },
Kailang Yang83c34212007-07-05 11:43:05 +020011957 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11958 .dac_nids = alc262_dac_nids,
11959 .hp_nid = 0x03,
11960 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11961 .channel_mode = alc262_modes,
11962 .input_mux = &alc262_capture_source,
11963 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011964 .setup = alc262_hippo_setup,
11965 .init_hook = alc262_hippo_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020011966 },
Tobin Davisf651b502007-10-26 12:40:47 +020011967 [ALC262_ULTRA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010011968 .mixers = { alc262_ultra_mixer },
11969 .cap_mixer = alc262_ultra_capture_mixer,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011970 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +020011971 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11972 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +020011973 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11974 .channel_mode = alc262_modes,
11975 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011976 .adc_nids = alc262_adc_nids, /* ADC0 */
11977 .capsrc_nids = alc262_capsrc_nids,
11978 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +020011979 .unsol_event = alc262_ultra_unsol_event,
11980 .init_hook = alc262_ultra_automute,
11981 },
Jiang zhe0e31daf2008-03-20 12:12:39 +010011982 [ALC262_LENOVO_3000] = {
11983 .mixers = { alc262_lenovo_3000_mixer },
11984 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
Daniel T Chene2595322009-12-19 18:19:02 -050011985 alc262_lenovo_3000_unsol_verbs,
11986 alc262_lenovo_3000_init_verbs },
Jiang zhe0e31daf2008-03-20 12:12:39 +010011987 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11988 .dac_nids = alc262_dac_nids,
11989 .hp_nid = 0x03,
11990 .dig_out_nid = ALC262_DIGOUT_NID,
11991 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11992 .channel_mode = alc262_modes,
11993 .input_mux = &alc262_fujitsu_capture_source,
11994 .unsol_event = alc262_lenovo_3000_unsol_event,
11995 },
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011996 [ALC262_NEC] = {
11997 .mixers = { alc262_nec_mixer },
11998 .init_verbs = { alc262_nec_verbs },
11999 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12000 .dac_nids = alc262_dac_nids,
12001 .hp_nid = 0x03,
12002 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12003 .channel_mode = alc262_modes,
12004 .input_mux = &alc262_capture_source,
12005 },
Kailang Yang4e555fe2008-08-26 13:05:55 +020012006 [ALC262_TOSHIBA_S06] = {
12007 .mixers = { alc262_toshiba_s06_mixer },
12008 .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
12009 alc262_eapd_verbs },
12010 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12011 .capsrc_nids = alc262_dmic_capsrc_nids,
12012 .dac_nids = alc262_dac_nids,
12013 .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
Takashi Iwaiae14ef62009-06-22 08:16:56 +020012014 .num_adc_nids = 1, /* single ADC */
Kailang Yang4e555fe2008-08-26 13:05:55 +020012015 .dig_out_nid = ALC262_DIGOUT_NID,
12016 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12017 .channel_mode = alc262_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012018 .unsol_event = alc_sku_unsol_event,
12019 .setup = alc262_toshiba_s06_setup,
12020 .init_hook = alc_inithook,
Kailang Yang4e555fe2008-08-26 13:05:55 +020012021 },
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012022 [ALC262_TOSHIBA_RX1] = {
12023 .mixers = { alc262_toshiba_rx1_mixer },
12024 .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
12025 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12026 .dac_nids = alc262_dac_nids,
12027 .hp_nid = 0x03,
12028 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12029 .channel_mode = alc262_modes,
12030 .input_mux = &alc262_capture_source,
12031 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012032 .setup = alc262_hippo_setup,
12033 .init_hook = alc262_hippo_automute,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012034 },
Tony Vroonba340e82009-02-02 19:01:30 +000012035 [ALC262_TYAN] = {
12036 .mixers = { alc262_tyan_mixer },
12037 .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
12038 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12039 .dac_nids = alc262_dac_nids,
12040 .hp_nid = 0x02,
12041 .dig_out_nid = ALC262_DIGOUT_NID,
12042 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12043 .channel_mode = alc262_modes,
12044 .input_mux = &alc262_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012045 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012046 .setup = alc262_tyan_setup,
12047 .init_hook = alc_automute_amp,
Tony Vroonba340e82009-02-02 19:01:30 +000012048 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012049};
12050
12051static int patch_alc262(struct hda_codec *codec)
12052{
12053 struct alc_spec *spec;
12054 int board_config;
12055 int err;
12056
Robert P. J. Daydc041e02006-12-19 14:44:15 +010012057 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010012058 if (spec == NULL)
12059 return -ENOMEM;
12060
12061 codec->spec = spec;
12062#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012063 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
12064 * under-run
12065 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012066 {
12067 int tmp;
12068 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
12069 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
12070 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
12071 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
12072 }
12073#endif
12074
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020012075 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
12076
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012077 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
12078 alc262_models,
12079 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +010012080
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012081 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020012082 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
12083 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010012084 board_config = ALC262_AUTO;
12085 }
12086
12087 if (board_config == ALC262_AUTO) {
12088 /* automatic parse from the BIOS config */
12089 err = alc262_parse_auto_config(codec);
12090 if (err < 0) {
12091 alc_free(codec);
12092 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012093 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012094 printk(KERN_INFO
12095 "hda_codec: Cannot set up configuration "
12096 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010012097 board_config = ALC262_BASIC;
12098 }
12099 }
12100
Takashi Iwai07eba612009-02-19 08:06:35 +010012101 if (!spec->no_analog) {
12102 err = snd_hda_attach_beep_device(codec, 0x1);
12103 if (err < 0) {
12104 alc_free(codec);
12105 return err;
12106 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090012107 }
12108
Kailang Yangdf694da2005-12-05 19:42:22 +010012109 if (board_config != ALC262_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020012110 setup_preset(codec, &alc262_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010012111
Kailang Yangdf694da2005-12-05 19:42:22 +010012112 spec->stream_analog_playback = &alc262_pcm_analog_playback;
12113 spec->stream_analog_capture = &alc262_pcm_analog_capture;
Kailang Yangea1fb292008-08-26 12:58:38 +020012114
Kailang Yangdf694da2005-12-05 19:42:22 +010012115 spec->stream_digital_playback = &alc262_pcm_digital_playback;
12116 spec->stream_digital_capture = &alc262_pcm_digital_capture;
12117
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012118 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwai8c927b42009-06-22 10:56:54 +020012119 int i;
12120 /* check whether the digital-mic has to be supported */
12121 for (i = 0; i < spec->input_mux->num_items; i++) {
12122 if (spec->input_mux->items[i].index >= 9)
12123 break;
12124 }
12125 if (i < spec->input_mux->num_items) {
12126 /* use only ADC0 */
12127 spec->adc_nids = alc262_dmic_adc_nids;
12128 spec->num_adc_nids = 1;
12129 spec->capsrc_nids = alc262_dmic_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +010012130 } else {
Takashi Iwai8c927b42009-06-22 10:56:54 +020012131 /* all analog inputs */
12132 /* check whether NID 0x07 is valid */
12133 unsigned int wcap = get_wcaps(codec, 0x07);
12134
12135 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020012136 wcap = get_wcaps_type(wcap);
Takashi Iwai8c927b42009-06-22 10:56:54 +020012137 if (wcap != AC_WID_AUD_IN) {
12138 spec->adc_nids = alc262_adc_nids_alt;
12139 spec->num_adc_nids =
12140 ARRAY_SIZE(alc262_adc_nids_alt);
12141 spec->capsrc_nids = alc262_capsrc_nids_alt;
12142 } else {
12143 spec->adc_nids = alc262_adc_nids;
12144 spec->num_adc_nids =
12145 ARRAY_SIZE(alc262_adc_nids);
12146 spec->capsrc_nids = alc262_capsrc_nids;
12147 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012148 }
12149 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012150 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020012151 set_capture_mixer(codec);
Takashi Iwai07eba612009-02-19 08:06:35 +010012152 if (!spec->no_analog)
12153 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Kailang Yangdf694da2005-12-05 19:42:22 +010012154
Takashi Iwai2134ea42008-01-10 16:53:55 +010012155 spec->vmaster_nid = 0x0c;
12156
Kailang Yangdf694da2005-12-05 19:42:22 +010012157 codec->patch_ops = alc_patch_ops;
12158 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012159 spec->init_hook = alc262_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020012160#ifdef CONFIG_SND_HDA_POWER_SAVE
12161 if (!spec->loopback.amplist)
12162 spec->loopback.amplist = alc262_loopbacks;
12163#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020012164
Kailang Yangdf694da2005-12-05 19:42:22 +010012165 return 0;
12166}
12167
Kailang Yangdf694da2005-12-05 19:42:22 +010012168/*
Kailang Yanga361d842007-06-05 12:30:55 +020012169 * ALC268 channel source setting (2 channel)
12170 */
12171#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
12172#define alc268_modes alc260_modes
Kailang Yangea1fb292008-08-26 12:58:38 +020012173
Kailang Yanga361d842007-06-05 12:30:55 +020012174static hda_nid_t alc268_dac_nids[2] = {
12175 /* front, hp */
12176 0x02, 0x03
12177};
12178
12179static hda_nid_t alc268_adc_nids[2] = {
12180 /* ADC0-1 */
12181 0x08, 0x07
12182};
12183
12184static hda_nid_t alc268_adc_nids_alt[1] = {
12185 /* ADC0 */
12186 0x08
12187};
12188
Takashi Iwaie1406342008-02-11 18:32:32 +010012189static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
12190
Kailang Yanga361d842007-06-05 12:30:55 +020012191static struct snd_kcontrol_new alc268_base_mixer[] = {
12192 /* output mixer control */
12193 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12194 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12195 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12196 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai33bf17a2007-08-21 11:51:42 +020012197 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12198 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12199 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +020012200 { }
12201};
12202
Takashi Iwai42171c12009-05-08 14:11:43 +020012203static struct snd_kcontrol_new alc268_toshiba_mixer[] = {
12204 /* output mixer control */
12205 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12206 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12207 ALC262_HIPPO_MASTER_SWITCH,
12208 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12209 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12210 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
12211 { }
12212};
12213
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012214/* bind Beep switches of both NID 0x0f and 0x10 */
12215static struct hda_bind_ctls alc268_bind_beep_sw = {
12216 .ops = &snd_hda_bind_sw,
12217 .values = {
12218 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
12219 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
12220 0
12221 },
12222};
12223
12224static struct snd_kcontrol_new alc268_beep_mixer[] = {
12225 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
12226 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
12227 { }
12228};
12229
Kailang Yangd1a991a2007-08-15 16:21:59 +020012230static struct hda_verb alc268_eapd_verbs[] = {
12231 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
12232 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
12233 { }
12234};
12235
Takashi Iwaid2738092007-08-16 14:59:45 +020012236/* Toshiba specific */
Takashi Iwaid2738092007-08-16 14:59:45 +020012237static struct hda_verb alc268_toshiba_verbs[] = {
12238 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12239 { } /* end */
12240};
12241
12242/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +020012243/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +020012244static struct hda_bind_ctls alc268_acer_bind_master_vol = {
12245 .ops = &snd_hda_bind_vol,
12246 .values = {
12247 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
12248 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
12249 0
12250 },
12251};
12252
Takashi Iwai889c4392007-08-23 18:56:52 +020012253/* mute/unmute internal speaker according to the hp jack and mute state */
12254static void alc268_acer_automute(struct hda_codec *codec, int force)
12255{
12256 struct alc_spec *spec = codec->spec;
12257 unsigned int mute;
12258
12259 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080012260 spec->jack_present = snd_hda_jack_detect(codec, 0x14);
Takashi Iwai889c4392007-08-23 18:56:52 +020012261 spec->sense_updated = 1;
12262 }
12263 if (spec->jack_present)
12264 mute = HDA_AMP_MUTE; /* mute internal speaker */
12265 else /* unmute internal speaker if necessary */
12266 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
12267 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
12268 HDA_AMP_MUTE, mute);
12269}
12270
12271
12272/* bind hp and internal speaker mute (with plug check) */
12273static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
12274 struct snd_ctl_elem_value *ucontrol)
12275{
12276 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
12277 long *valp = ucontrol->value.integer.value;
12278 int change;
12279
Takashi Iwai8de56b72009-07-24 16:51:47 +020012280 change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
Takashi Iwai889c4392007-08-23 18:56:52 +020012281 if (change)
12282 alc268_acer_automute(codec, 0);
12283 return change;
12284}
Takashi Iwaid2738092007-08-16 14:59:45 +020012285
Kailang Yang8ef355d2008-08-26 13:10:22 +020012286static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
12287 /* output mixer control */
12288 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12289 {
12290 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12291 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010012292 .subdevice = HDA_SUBDEV_AMP_FLAG,
Kailang Yang8ef355d2008-08-26 13:10:22 +020012293 .info = snd_hda_mixer_amp_switch_info,
12294 .get = snd_hda_mixer_amp_switch_get,
12295 .put = alc268_acer_master_sw_put,
12296 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12297 },
12298 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
12299 { }
12300};
12301
Takashi Iwaid2738092007-08-16 14:59:45 +020012302static struct snd_kcontrol_new alc268_acer_mixer[] = {
12303 /* output mixer control */
12304 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12305 {
12306 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12307 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010012308 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwaid2738092007-08-16 14:59:45 +020012309 .info = snd_hda_mixer_amp_switch_info,
12310 .get = snd_hda_mixer_amp_switch_get,
12311 .put = alc268_acer_master_sw_put,
12312 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12313 },
Takashi Iwai33bf17a2007-08-21 11:51:42 +020012314 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12315 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
12316 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +020012317 { }
12318};
12319
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012320static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
12321 /* output mixer control */
12322 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12323 {
12324 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12325 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010012326 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012327 .info = snd_hda_mixer_amp_switch_info,
12328 .get = snd_hda_mixer_amp_switch_get,
12329 .put = alc268_acer_master_sw_put,
12330 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12331 },
12332 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12333 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
12334 { }
12335};
12336
Kailang Yang8ef355d2008-08-26 13:10:22 +020012337static struct hda_verb alc268_acer_aspire_one_verbs[] = {
12338 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12339 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12340 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12341 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12342 {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
12343 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
12344 { }
12345};
12346
Takashi Iwaid2738092007-08-16 14:59:45 +020012347static struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012348 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
12349 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +020012350 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12351 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012352 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12353 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +020012354 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12355 { }
12356};
12357
12358/* unsolicited event for HP jack sensing */
Takashi Iwai42171c12009-05-08 14:11:43 +020012359#define alc268_toshiba_unsol_event alc262_hippo_unsol_event
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012360#define alc268_toshiba_setup alc262_hippo_setup
12361#define alc268_toshiba_automute alc262_hippo_automute
Takashi Iwaid2738092007-08-16 14:59:45 +020012362
12363static void alc268_acer_unsol_event(struct hda_codec *codec,
12364 unsigned int res)
12365{
Takashi Iwai889c4392007-08-23 18:56:52 +020012366 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020012367 return;
12368 alc268_acer_automute(codec, 1);
12369}
12370
Takashi Iwai889c4392007-08-23 18:56:52 +020012371static void alc268_acer_init_hook(struct hda_codec *codec)
12372{
12373 alc268_acer_automute(codec, 1);
12374}
12375
Kailang Yang8ef355d2008-08-26 13:10:22 +020012376/* toggle speaker-output according to the hp-jack state */
12377static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
12378{
12379 unsigned int present;
12380 unsigned char bits;
12381
Wu Fengguang864f92b2009-11-18 12:38:02 +080012382 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yang8ef355d2008-08-26 13:10:22 +020012383 bits = present ? AMP_IN_MUTE(0) : 0;
12384 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
12385 AMP_IN_MUTE(0), bits);
12386 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1,
12387 AMP_IN_MUTE(0), bits);
12388}
12389
Kailang Yang8ef355d2008-08-26 13:10:22 +020012390static void alc268_acer_lc_unsol_event(struct hda_codec *codec,
12391 unsigned int res)
12392{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012393 switch (res >> 26) {
12394 case ALC880_HP_EVENT:
Kailang Yang8ef355d2008-08-26 13:10:22 +020012395 alc268_aspire_one_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012396 break;
12397 case ALC880_MIC_EVENT:
12398 alc_mic_automute(codec);
12399 break;
12400 }
12401}
12402
12403static void alc268_acer_lc_setup(struct hda_codec *codec)
12404{
12405 struct alc_spec *spec = codec->spec;
12406 spec->ext_mic.pin = 0x18;
12407 spec->ext_mic.mux_idx = 0;
12408 spec->int_mic.pin = 0x12;
12409 spec->int_mic.mux_idx = 6;
12410 spec->auto_mic = 1;
Kailang Yang8ef355d2008-08-26 13:10:22 +020012411}
12412
12413static void alc268_acer_lc_init_hook(struct hda_codec *codec)
12414{
12415 alc268_aspire_one_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012416 alc_mic_automute(codec);
Kailang Yang8ef355d2008-08-26 13:10:22 +020012417}
12418
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012419static struct snd_kcontrol_new alc268_dell_mixer[] = {
12420 /* output mixer control */
12421 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12422 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12423 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12424 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12425 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12426 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
12427 { }
12428};
12429
12430static struct hda_verb alc268_dell_verbs[] = {
12431 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12432 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12433 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012434 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012435 { }
12436};
12437
12438/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012439static void alc268_dell_setup(struct hda_codec *codec)
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012440{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012441 struct alc_spec *spec = codec->spec;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012442
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012443 spec->autocfg.hp_pins[0] = 0x15;
12444 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012445 spec->ext_mic.pin = 0x18;
12446 spec->ext_mic.mux_idx = 0;
12447 spec->int_mic.pin = 0x19;
12448 spec->int_mic.mux_idx = 1;
12449 spec->auto_mic = 1;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012450}
12451
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012452static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
12453 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12454 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12455 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12456 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12457 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
12458 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
12459 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
12460 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
12461 { }
12462};
12463
12464static struct hda_verb alc267_quanta_il1_verbs[] = {
12465 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12466 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
12467 { }
12468};
12469
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012470static void alc267_quanta_il1_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012471{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012472 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012473 spec->autocfg.hp_pins[0] = 0x15;
12474 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012475 spec->ext_mic.pin = 0x18;
12476 spec->ext_mic.mux_idx = 0;
12477 spec->int_mic.pin = 0x19;
12478 spec->int_mic.mux_idx = 1;
12479 spec->auto_mic = 1;
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012480}
12481
Kailang Yanga361d842007-06-05 12:30:55 +020012482/*
12483 * generic initialization of ADC, input mixers and output mixers
12484 */
12485static struct hda_verb alc268_base_init_verbs[] = {
12486 /* Unmute DAC0-1 and set vol = 0 */
12487 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020012488 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020012489
12490 /*
12491 * Set up output mixers (0x0c - 0x0e)
12492 */
12493 /* set vol=0 to output mixers */
12494 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020012495 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
12496
12497 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12498 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12499
12500 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
12501 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
12502 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
12503 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12504 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12505 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12506 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12507 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12508
12509 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12510 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12511 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12512 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020012513 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012514
12515 /* set PCBEEP vol = 0, mute connections */
12516 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12517 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12518 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020012519
Jiang Zhea9b3aa82007-12-20 13:13:13 +010012520 /* Unmute Selector 23h,24h and set the default input to mic-in */
Kailang Yangea1fb292008-08-26 12:58:38 +020012521
Jiang Zhea9b3aa82007-12-20 13:13:13 +010012522 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
12523 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12524 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
12525 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020012526
Kailang Yanga361d842007-06-05 12:30:55 +020012527 { }
12528};
12529
12530/*
12531 * generic initialization of ADC, input mixers and output mixers
12532 */
12533static struct hda_verb alc268_volume_init_verbs[] = {
12534 /* set output DAC */
Takashi Iwai4cfb91c2009-01-23 12:53:09 +010012535 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12536 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020012537
12538 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12539 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12540 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12541 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12542 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12543
Kailang Yanga361d842007-06-05 12:30:55 +020012544 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020012545 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12546 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12547
12548 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020012549 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020012550
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012551 /* set PCBEEP vol = 0, mute connections */
12552 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12553 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12554 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020012555
12556 { }
12557};
12558
Takashi Iwaifdbc66262009-08-19 00:18:10 +020012559static struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = {
12560 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
12561 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
12562 { } /* end */
12563};
12564
Kailang Yanga361d842007-06-05 12:30:55 +020012565static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
12566 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
12567 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc66262009-08-19 00:18:10 +020012568 _DEFINE_CAPSRC(1),
Kailang Yanga361d842007-06-05 12:30:55 +020012569 { } /* end */
12570};
12571
12572static struct snd_kcontrol_new alc268_capture_mixer[] = {
12573 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
12574 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
12575 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
12576 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc66262009-08-19 00:18:10 +020012577 _DEFINE_CAPSRC(2),
Kailang Yanga361d842007-06-05 12:30:55 +020012578 { } /* end */
12579};
12580
12581static struct hda_input_mux alc268_capture_source = {
12582 .num_items = 4,
12583 .items = {
12584 { "Mic", 0x0 },
12585 { "Front Mic", 0x1 },
12586 { "Line", 0x2 },
12587 { "CD", 0x3 },
12588 },
12589};
12590
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012591static struct hda_input_mux alc268_acer_capture_source = {
12592 .num_items = 3,
12593 .items = {
12594 { "Mic", 0x0 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012595 { "Internal Mic", 0x1 },
12596 { "Line", 0x2 },
12597 },
12598};
12599
12600static struct hda_input_mux alc268_acer_dmic_capture_source = {
12601 .num_items = 3,
12602 .items = {
12603 { "Mic", 0x0 },
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012604 { "Internal Mic", 0x6 },
12605 { "Line", 0x2 },
12606 },
12607};
12608
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010012609#ifdef CONFIG_SND_DEBUG
12610static struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010012611 /* Volume widgets */
12612 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12613 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12614 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
12615 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
12616 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
12617 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
12618 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
12619 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
12620 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
12621 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
12622 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
12623 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
12624 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010012625 /* The below appears problematic on some hardwares */
12626 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010012627 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
12628 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
12629 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
12630 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
12631
12632 /* Modes for retasking pin widgets */
12633 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
12634 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
12635 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
12636 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
12637
12638 /* Controls for GPIO pins, assuming they are configured as outputs */
12639 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
12640 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
12641 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
12642 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
12643
12644 /* Switches to allow the digital SPDIF output pin to be enabled.
12645 * The ALC268 does not have an SPDIF input.
12646 */
12647 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
12648
12649 /* A switch allowing EAPD to be enabled. Some laptops seem to use
12650 * this output to turn on an external amplifier.
12651 */
12652 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
12653 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
12654
12655 { } /* end */
12656};
12657#endif
12658
Kailang Yanga361d842007-06-05 12:30:55 +020012659/* create input playback/capture controls for the given pin */
12660static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
12661 const char *ctlname, int idx)
12662{
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012663 hda_nid_t dac;
Kailang Yanga361d842007-06-05 12:30:55 +020012664 int err;
12665
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012666 switch (nid) {
12667 case 0x14:
12668 case 0x16:
12669 dac = 0x02;
12670 break;
12671 case 0x15:
Takashi Iwai4feabef2010-01-19 15:38:44 +010012672 case 0x21:
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012673 dac = 0x03;
12674 break;
12675 default:
12676 return 0;
12677 }
12678 if (spec->multiout.dac_nids[0] != dac &&
12679 spec->multiout.dac_nids[1] != dac) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020012680 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012681 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
Kailang Yanga361d842007-06-05 12:30:55 +020012682 HDA_OUTPUT));
12683 if (err < 0)
12684 return err;
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012685 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
12686 }
12687
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012688 if (nid != 0x16)
Takashi Iwai0afe5f82009-10-02 09:20:00 +020012689 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Kailang Yanga361d842007-06-05 12:30:55 +020012690 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012691 else /* mono */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020012692 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012693 HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020012694 if (err < 0)
12695 return err;
12696 return 0;
12697}
12698
12699/* add playback controls from the parsed DAC table */
12700static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
12701 const struct auto_pin_cfg *cfg)
12702{
12703 hda_nid_t nid;
12704 int err;
12705
Kailang Yanga361d842007-06-05 12:30:55 +020012706 spec->multiout.dac_nids = spec->private_dac_nids;
Kailang Yanga361d842007-06-05 12:30:55 +020012707
12708 nid = cfg->line_out_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012709 if (nid) {
12710 const char *name;
12711 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
12712 name = "Speaker";
12713 else
12714 name = "Front";
12715 err = alc268_new_analog_output(spec, nid, name, 0);
12716 if (err < 0)
12717 return err;
12718 }
Kailang Yanga361d842007-06-05 12:30:55 +020012719
12720 nid = cfg->speaker_pins[0];
12721 if (nid == 0x1d) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020012722 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Speaker",
Kailang Yanga361d842007-06-05 12:30:55 +020012723 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
12724 if (err < 0)
12725 return err;
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012726 } else {
12727 err = alc268_new_analog_output(spec, nid, "Speaker", 0);
12728 if (err < 0)
12729 return err;
Kailang Yanga361d842007-06-05 12:30:55 +020012730 }
12731 nid = cfg->hp_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012732 if (nid) {
12733 err = alc268_new_analog_output(spec, nid, "Headphone", 0);
12734 if (err < 0)
12735 return err;
12736 }
Kailang Yanga361d842007-06-05 12:30:55 +020012737
12738 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
12739 if (nid == 0x16) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020012740 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, "Mono",
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012741 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020012742 if (err < 0)
12743 return err;
12744 }
Kailang Yangea1fb292008-08-26 12:58:38 +020012745 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020012746}
12747
12748/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020012749static int alc268_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yanga361d842007-06-05 12:30:55 +020012750 const struct auto_pin_cfg *cfg)
12751{
Takashi Iwai05f5f472009-08-25 13:10:18 +020012752 return alc_auto_create_input_ctls(codec, cfg, 0, 0x23, 0x24);
Kailang Yanga361d842007-06-05 12:30:55 +020012753}
12754
Takashi Iwaie9af4f32009-08-29 23:23:08 +020012755static void alc268_auto_set_output_and_unmute(struct hda_codec *codec,
12756 hda_nid_t nid, int pin_type)
12757{
12758 int idx;
12759
12760 alc_set_pin_output(codec, nid, pin_type);
12761 if (nid == 0x14 || nid == 0x16)
12762 idx = 0;
12763 else
12764 idx = 1;
12765 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
12766}
12767
12768static void alc268_auto_init_multi_out(struct hda_codec *codec)
12769{
12770 struct alc_spec *spec = codec->spec;
12771 hda_nid_t nid = spec->autocfg.line_out_pins[0];
12772 if (nid) {
12773 int pin_type = get_pin_type(spec->autocfg.line_out_type);
12774 alc268_auto_set_output_and_unmute(codec, nid, pin_type);
12775 }
12776}
12777
12778static void alc268_auto_init_hp_out(struct hda_codec *codec)
12779{
12780 struct alc_spec *spec = codec->spec;
12781 hda_nid_t pin;
12782
12783 pin = spec->autocfg.hp_pins[0];
12784 if (pin)
12785 alc268_auto_set_output_and_unmute(codec, pin, PIN_HP);
12786 pin = spec->autocfg.speaker_pins[0];
12787 if (pin)
12788 alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT);
12789}
12790
Kailang Yanga361d842007-06-05 12:30:55 +020012791static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
12792{
12793 struct alc_spec *spec = codec->spec;
12794 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
12795 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
12796 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
12797 unsigned int dac_vol1, dac_vol2;
12798
Takashi Iwaie9af4f32009-08-29 23:23:08 +020012799 if (line_nid == 0x1d || speaker_nid == 0x1d) {
Kailang Yanga361d842007-06-05 12:30:55 +020012800 snd_hda_codec_write(codec, speaker_nid, 0,
12801 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020012802 /* mute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020012803 snd_hda_codec_write(codec, 0x0f, 0,
12804 AC_VERB_SET_AMP_GAIN_MUTE,
12805 AMP_IN_UNMUTE(1));
12806 snd_hda_codec_write(codec, 0x10, 0,
12807 AC_VERB_SET_AMP_GAIN_MUTE,
12808 AMP_IN_UNMUTE(1));
12809 } else {
Takashi Iwaie9af4f32009-08-29 23:23:08 +020012810 /* unmute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020012811 snd_hda_codec_write(codec, 0x0f, 0,
12812 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
12813 snd_hda_codec_write(codec, 0x10, 0,
12814 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
12815 }
12816
12817 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020012818 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020012819 dac_vol2 = AMP_OUT_ZERO;
12820 else if (line_nid == 0x15)
12821 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020012822 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020012823 dac_vol2 = AMP_OUT_ZERO;
12824 else if (hp_nid == 0x15)
12825 dac_vol1 = AMP_OUT_ZERO;
12826 if (line_nid != 0x16 || hp_nid != 0x16 ||
12827 spec->autocfg.line_out_pins[1] != 0x16 ||
12828 spec->autocfg.line_out_pins[2] != 0x16)
12829 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
12830
12831 snd_hda_codec_write(codec, 0x02, 0,
12832 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
12833 snd_hda_codec_write(codec, 0x03, 0,
12834 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
12835}
12836
Sasha Alexandrdef319f2009-06-16 16:00:15 -040012837/* pcm configuration: identical with ALC880 */
Kailang Yanga361d842007-06-05 12:30:55 +020012838#define alc268_pcm_analog_playback alc880_pcm_analog_playback
12839#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010012840#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020012841#define alc268_pcm_digital_playback alc880_pcm_digital_playback
12842
12843/*
12844 * BIOS auto configuration
12845 */
12846static int alc268_parse_auto_config(struct hda_codec *codec)
12847{
12848 struct alc_spec *spec = codec->spec;
12849 int err;
12850 static hda_nid_t alc268_ignore[] = { 0 };
12851
12852 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12853 alc268_ignore);
12854 if (err < 0)
12855 return err;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012856 if (!spec->autocfg.line_outs) {
12857 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
12858 spec->multiout.max_channels = 2;
12859 spec->no_analog = 1;
12860 goto dig_only;
12861 }
Kailang Yanga361d842007-06-05 12:30:55 +020012862 return 0; /* can't find valid BIOS pin config */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012863 }
Kailang Yanga361d842007-06-05 12:30:55 +020012864 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
12865 if (err < 0)
12866 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020012867 err = alc268_auto_create_input_ctls(codec, &spec->autocfg);
Kailang Yanga361d842007-06-05 12:30:55 +020012868 if (err < 0)
12869 return err;
12870
12871 spec->multiout.max_channels = 2;
12872
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012873 dig_only:
Kailang Yanga361d842007-06-05 12:30:55 +020012874 /* digital only support output */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012875 if (spec->autocfg.dig_outs) {
Kailang Yanga361d842007-06-05 12:30:55 +020012876 spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012877 spec->dig_out_type = spec->autocfg.dig_out_type[0];
12878 }
Takashi Iwai603c4012008-07-30 15:01:44 +020012879 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012880 add_mixer(spec, spec->kctls.list);
Kailang Yanga361d842007-06-05 12:30:55 +020012881
Takashi Iwai892981f2009-03-02 08:04:35 +010012882 if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012883 add_mixer(spec, alc268_beep_mixer);
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012884
Takashi Iwaid88897e2008-10-31 15:01:37 +010012885 add_verb(spec, alc268_volume_init_verbs);
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030012886 spec->num_mux_defs = 2;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020012887 spec->input_mux = &spec->private_imux[0];
Kailang Yanga361d842007-06-05 12:30:55 +020012888
Takashi Iwai776e1842007-08-29 15:07:11 +020012889 err = alc_auto_add_mic_boost(codec);
12890 if (err < 0)
12891 return err;
12892
Takashi Iwai1d955eb2009-06-29 11:33:53 +020012893 alc_ssid_check(codec, 0x15, 0x1b, 0x14);
12894
Kailang Yanga361d842007-06-05 12:30:55 +020012895 return 1;
12896}
12897
Kailang Yanga361d842007-06-05 12:30:55 +020012898#define alc268_auto_init_analog_input alc882_auto_init_analog_input
12899
12900/* init callback for auto-configuration model -- overriding the default init */
12901static void alc268_auto_init(struct hda_codec *codec)
12902{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012903 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020012904 alc268_auto_init_multi_out(codec);
12905 alc268_auto_init_hp_out(codec);
12906 alc268_auto_init_mono_speaker_out(codec);
12907 alc268_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012908 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020012909 alc_inithook(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020012910}
12911
12912/*
12913 * configuration and preset
12914 */
12915static const char *alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012916 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020012917 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020012918 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020012919 [ALC268_ACER] = "acer",
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012920 [ALC268_ACER_DMIC] = "acer-dmic",
Kailang Yang8ef355d2008-08-26 13:10:22 +020012921 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012922 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012923 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010012924#ifdef CONFIG_SND_DEBUG
12925 [ALC268_TEST] = "test",
12926#endif
Kailang Yanga361d842007-06-05 12:30:55 +020012927 [ALC268_AUTO] = "auto",
12928};
12929
12930static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020012931 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012932 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010012933 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012934 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010012935 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020012936 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
12937 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012938 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Daniel T Chena1bf8082009-11-01 18:32:29 -050012939 SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0,
12940 "Dell Inspiron Mini9/Vostro A90", ALC268_DELL),
Takashi Iwai33d78672009-09-08 11:03:41 +020012941 /* almost compatible with toshiba but with optional digital outs;
12942 * auto-probing seems working fine
12943 */
Takashi Iwai8871e5b2009-06-02 01:02:50 +020012944 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series",
Takashi Iwai33d78672009-09-08 11:03:41 +020012945 ALC268_AUTO),
Kailang Yanga361d842007-06-05 12:30:55 +020012946 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020012947 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Tony Vroon378bd6a2008-06-04 12:08:30 +020012948 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020012949 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012950 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020012951 SND_PCI_QUIRK(0x1854, 0x1775, "LG R510", ALC268_DELL),
Kailang Yanga361d842007-06-05 12:30:55 +020012952 {}
12953};
12954
Takashi Iwai3abf2f32009-08-19 20:05:02 +020012955/* Toshiba laptops have no unique PCI SSID but only codec SSID */
12956static struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
12957 SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO),
12958 SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO),
12959 SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
12960 ALC268_TOSHIBA),
12961 {}
12962};
12963
Kailang Yanga361d842007-06-05 12:30:55 +020012964static struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012965 [ALC267_QUANTA_IL1] = {
Takashi Iwaifdbc66262009-08-19 00:18:10 +020012966 .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer,
12967 alc268_capture_nosrc_mixer },
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012968 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12969 alc267_quanta_il1_verbs },
12970 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12971 .dac_nids = alc268_dac_nids,
12972 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12973 .adc_nids = alc268_adc_nids_alt,
12974 .hp_nid = 0x03,
12975 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12976 .channel_mode = alc268_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012977 .unsol_event = alc_sku_unsol_event,
12978 .setup = alc267_quanta_il1_setup,
12979 .init_hook = alc_inithook,
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012980 },
Kailang Yanga361d842007-06-05 12:30:55 +020012981 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012982 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
12983 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020012984 .init_verbs = { alc268_base_init_verbs },
12985 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12986 .dac_nids = alc268_dac_nids,
12987 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12988 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010012989 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020012990 .hp_nid = 0x03,
12991 .dig_out_nid = ALC268_DIGOUT_NID,
12992 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12993 .channel_mode = alc268_modes,
12994 .input_mux = &alc268_capture_source,
12995 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020012996 [ALC268_TOSHIBA] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020012997 .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012998 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020012999 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13000 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013001 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13002 .dac_nids = alc268_dac_nids,
13003 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13004 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013005 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013006 .hp_nid = 0x03,
13007 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13008 .channel_mode = alc268_modes,
13009 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020013010 .unsol_event = alc268_toshiba_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013011 .setup = alc268_toshiba_setup,
13012 .init_hook = alc268_toshiba_automute,
Takashi Iwaid2738092007-08-16 14:59:45 +020013013 },
13014 [ALC268_ACER] = {
Takashi Iwai432fd132009-09-30 08:13:44 +020013015 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013016 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013017 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13018 alc268_acer_verbs },
13019 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13020 .dac_nids = alc268_dac_nids,
13021 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13022 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013023 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020013024 .hp_nid = 0x02,
13025 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13026 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013027 .input_mux = &alc268_acer_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020013028 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020013029 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013030 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013031 [ALC268_ACER_DMIC] = {
13032 .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
13033 alc268_beep_mixer },
13034 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13035 alc268_acer_verbs },
13036 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13037 .dac_nids = alc268_dac_nids,
13038 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13039 .adc_nids = alc268_adc_nids_alt,
13040 .capsrc_nids = alc268_capsrc_nids,
13041 .hp_nid = 0x02,
13042 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13043 .channel_mode = alc268_modes,
13044 .input_mux = &alc268_acer_dmic_capture_source,
13045 .unsol_event = alc268_acer_unsol_event,
13046 .init_hook = alc268_acer_init_hook,
13047 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013048 [ALC268_ACER_ASPIRE_ONE] = {
13049 .mixers = { alc268_acer_aspire_one_mixer,
Takashi Iwai22971e32009-02-10 11:56:44 +010013050 alc268_beep_mixer,
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013051 alc268_capture_nosrc_mixer },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013052 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13053 alc268_acer_aspire_one_verbs },
13054 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13055 .dac_nids = alc268_dac_nids,
13056 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13057 .adc_nids = alc268_adc_nids_alt,
13058 .capsrc_nids = alc268_capsrc_nids,
13059 .hp_nid = 0x03,
13060 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13061 .channel_mode = alc268_modes,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013062 .unsol_event = alc268_acer_lc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013063 .setup = alc268_acer_lc_setup,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013064 .init_hook = alc268_acer_lc_init_hook,
13065 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013066 [ALC268_DELL] = {
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013067 .mixers = { alc268_dell_mixer, alc268_beep_mixer,
13068 alc268_capture_nosrc_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013069 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13070 alc268_dell_verbs },
13071 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13072 .dac_nids = alc268_dac_nids,
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013073 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13074 .adc_nids = alc268_adc_nids_alt,
13075 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013076 .hp_nid = 0x02,
13077 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13078 .channel_mode = alc268_modes,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013079 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013080 .setup = alc268_dell_setup,
13081 .init_hook = alc_inithook,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013082 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013083 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013084 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13085 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013086 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13087 alc268_toshiba_verbs },
13088 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13089 .dac_nids = alc268_dac_nids,
13090 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13091 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013092 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013093 .hp_nid = 0x03,
13094 .dig_out_nid = ALC268_DIGOUT_NID,
13095 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13096 .channel_mode = alc268_modes,
13097 .input_mux = &alc268_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013098 .setup = alc268_toshiba_setup,
13099 .init_hook = alc268_toshiba_automute,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013100 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013101#ifdef CONFIG_SND_DEBUG
13102 [ALC268_TEST] = {
13103 .mixers = { alc268_test_mixer, alc268_capture_mixer },
13104 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13105 alc268_volume_init_verbs },
13106 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13107 .dac_nids = alc268_dac_nids,
13108 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13109 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013110 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013111 .hp_nid = 0x03,
13112 .dig_out_nid = ALC268_DIGOUT_NID,
13113 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13114 .channel_mode = alc268_modes,
13115 .input_mux = &alc268_capture_source,
13116 },
13117#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013118};
13119
13120static int patch_alc268(struct hda_codec *codec)
13121{
13122 struct alc_spec *spec;
13123 int board_config;
Takashi Iwai22971e32009-02-10 11:56:44 +010013124 int i, has_beep, err;
Kailang Yanga361d842007-06-05 12:30:55 +020013125
Julia Lawallef86f582009-12-19 08:18:03 +010013126 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yanga361d842007-06-05 12:30:55 +020013127 if (spec == NULL)
13128 return -ENOMEM;
13129
13130 codec->spec = spec;
13131
13132 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
13133 alc268_models,
13134 alc268_cfg_tbl);
13135
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013136 if (board_config < 0 || board_config >= ALC268_MODEL_LAST)
13137 board_config = snd_hda_check_board_codec_sid_config(codec,
13138 ALC882_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl);
13139
Kailang Yanga361d842007-06-05 12:30:55 +020013140 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020013141 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
13142 codec->chip_name);
Kailang Yanga361d842007-06-05 12:30:55 +020013143 board_config = ALC268_AUTO;
13144 }
13145
13146 if (board_config == ALC268_AUTO) {
13147 /* automatic parse from the BIOS config */
13148 err = alc268_parse_auto_config(codec);
13149 if (err < 0) {
13150 alc_free(codec);
13151 return err;
13152 } else if (!err) {
13153 printk(KERN_INFO
13154 "hda_codec: Cannot set up configuration "
13155 "from BIOS. Using base mode...\n");
13156 board_config = ALC268_3ST;
13157 }
13158 }
13159
13160 if (board_config != ALC268_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020013161 setup_preset(codec, &alc268_presets[board_config]);
Kailang Yanga361d842007-06-05 12:30:55 +020013162
Kailang Yanga361d842007-06-05 12:30:55 +020013163 spec->stream_analog_playback = &alc268_pcm_analog_playback;
13164 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010013165 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020013166
Kailang Yanga361d842007-06-05 12:30:55 +020013167 spec->stream_digital_playback = &alc268_pcm_digital_playback;
13168
Takashi Iwai22971e32009-02-10 11:56:44 +010013169 has_beep = 0;
13170 for (i = 0; i < spec->num_mixers; i++) {
13171 if (spec->mixers[i] == alc268_beep_mixer) {
13172 has_beep = 1;
13173 break;
13174 }
13175 }
13176
13177 if (has_beep) {
13178 err = snd_hda_attach_beep_device(codec, 0x1);
13179 if (err < 0) {
13180 alc_free(codec);
13181 return err;
13182 }
13183 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
13184 /* override the amp caps for beep generator */
13185 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013186 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
13187 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
13188 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
13189 (0 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwai22971e32009-02-10 11:56:44 +010013190 }
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013191
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013192 if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013193 /* check whether NID 0x07 is valid */
13194 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwai85860c02008-02-19 15:00:15 +010013195 int i;
Kailang Yanga361d842007-06-05 12:30:55 +020013196
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020013197 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013198 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020013199 wcap = get_wcaps_type(wcap);
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013200 if (spec->auto_mic ||
13201 wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013202 spec->adc_nids = alc268_adc_nids_alt;
13203 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020013204 if (spec->auto_mic)
13205 fixup_automic_adc(codec);
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013206 if (spec->auto_mic || spec->input_mux->num_items == 1)
13207 add_mixer(spec, alc268_capture_nosrc_mixer);
13208 else
13209 add_mixer(spec, alc268_capture_alt_mixer);
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013210 } else {
13211 spec->adc_nids = alc268_adc_nids;
13212 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
Takashi Iwaid88897e2008-10-31 15:01:37 +010013213 add_mixer(spec, alc268_capture_mixer);
Kailang Yanga361d842007-06-05 12:30:55 +020013214 }
Takashi Iwai85860c02008-02-19 15:00:15 +010013215 /* set default input source */
13216 for (i = 0; i < spec->num_adc_nids; i++)
13217 snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
13218 0, AC_VERB_SET_CONNECT_SEL,
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030013219 i < spec->num_mux_defs ?
13220 spec->input_mux[i].items[0].index :
Takashi Iwai85860c02008-02-19 15:00:15 +010013221 spec->input_mux->items[0].index);
Kailang Yanga361d842007-06-05 12:30:55 +020013222 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010013223
13224 spec->vmaster_nid = 0x02;
13225
Kailang Yanga361d842007-06-05 12:30:55 +020013226 codec->patch_ops = alc_patch_ops;
13227 if (board_config == ALC268_AUTO)
13228 spec->init_hook = alc268_auto_init;
Kailang Yangea1fb292008-08-26 12:58:38 +020013229
Kailang Yanga361d842007-06-05 12:30:55 +020013230 return 0;
13231}
13232
13233/*
Kailang Yangf6a92242007-12-13 16:52:54 +010013234 * ALC269 channel source setting (2 channel)
13235 */
13236#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
13237
13238#define alc269_dac_nids alc260_dac_nids
13239
13240static hda_nid_t alc269_adc_nids[1] = {
13241 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020013242 0x08,
13243};
13244
Takashi Iwaie01bf502008-08-21 16:25:07 +020013245static hda_nid_t alc269_capsrc_nids[1] = {
13246 0x23,
13247};
13248
Kailang Yang84898e82010-02-04 14:16:14 +010013249static hda_nid_t alc269vb_adc_nids[1] = {
13250 /* ADC1 */
13251 0x09,
13252};
13253
13254static hda_nid_t alc269vb_capsrc_nids[1] = {
13255 0x22,
13256};
13257
Takashi Iwaie01bf502008-08-21 16:25:07 +020013258/* NOTE: ADC2 (0x07) is connected from a recording *MIXER* (0x24),
13259 * not a mux!
13260 */
13261
Kailang Yangf6a92242007-12-13 16:52:54 +010013262#define alc269_modes alc260_modes
13263#define alc269_capture_source alc880_lg_lw_capture_source
13264
13265static struct snd_kcontrol_new alc269_base_mixer[] = {
13266 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13267 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13268 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13269 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13270 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13271 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13272 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13273 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13274 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
13275 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
13276 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
13277 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
13278 { } /* end */
13279};
13280
Kailang Yang60db6b52008-08-26 13:13:00 +020013281static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
13282 /* output mixer control */
13283 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13284 {
13285 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13286 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013287 .subdevice = HDA_SUBDEV_AMP_FLAG,
Kailang Yang60db6b52008-08-26 13:13:00 +020013288 .info = snd_hda_mixer_amp_switch_info,
13289 .get = snd_hda_mixer_amp_switch_get,
13290 .put = alc268_acer_master_sw_put,
13291 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13292 },
13293 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13294 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13295 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13296 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13297 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
13298 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020013299 { }
13300};
13301
Tony Vroon64154832008-11-06 15:08:49 +000013302static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
13303 /* output mixer control */
13304 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13305 {
13306 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13307 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013308 .subdevice = HDA_SUBDEV_AMP_FLAG,
Tony Vroon64154832008-11-06 15:08:49 +000013309 .info = snd_hda_mixer_amp_switch_info,
13310 .get = snd_hda_mixer_amp_switch_get,
13311 .put = alc268_acer_master_sw_put,
13312 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13313 },
13314 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13315 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13316 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13317 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13318 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
13319 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
13320 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
13321 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
13322 HDA_CODEC_VOLUME("Dock Mic Boost", 0x1b, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000013323 { }
13324};
13325
Kailang Yang84898e82010-02-04 14:16:14 +010013326static struct snd_kcontrol_new alc269_laptop_mixer[] = {
Takashi Iwaiaa202452009-07-03 15:00:54 +020013327 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010013328 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwaiaa202452009-07-03 15:00:54 +020013329 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010013330 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yangf53281e2008-07-18 12:36:43 +020013331 { } /* end */
13332};
13333
Kailang Yang84898e82010-02-04 14:16:14 +010013334static struct snd_kcontrol_new alc269vb_laptop_mixer[] = {
13335 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13336 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13337 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
13338 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13339 { } /* end */
13340};
13341
Kailang Yangf6a92242007-12-13 16:52:54 +010013342/* capture mixer elements */
Kailang Yang84898e82010-02-04 14:16:14 +010013343static struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
13344 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
13345 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
13346 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13347 HDA_CODEC_VOLUME("IntMic Boost", 0x19, 0, HDA_INPUT),
13348 { } /* end */
13349};
13350
13351static struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = {
Kailang Yangf53281e2008-07-18 12:36:43 +020013352 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
13353 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Takashi Iwai26f5df22008-11-03 17:39:46 +010013354 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13355 { } /* end */
13356};
13357
Kailang Yang84898e82010-02-04 14:16:14 +010013358static struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
13359 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
13360 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
13361 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13362 HDA_CODEC_VOLUME("IntMic Boost", 0x19, 0, HDA_INPUT),
13363 { } /* end */
13364};
13365
13366static struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
13367 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
13368 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
13369 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13370 { } /* end */
13371};
13372
Takashi Iwai26f5df22008-11-03 17:39:46 +010013373/* FSC amilo */
Kailang Yang84898e82010-02-04 14:16:14 +010013374#define alc269_fujitsu_mixer alc269_laptop_mixer
Kailang Yangf53281e2008-07-18 12:36:43 +020013375
Kailang Yang60db6b52008-08-26 13:13:00 +020013376static struct hda_verb alc269_quanta_fl1_verbs[] = {
13377 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13378 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13379 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13380 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13381 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13382 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13383 { }
13384};
13385
Tony Vroon64154832008-11-06 15:08:49 +000013386static struct hda_verb alc269_lifebook_verbs[] = {
13387 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13388 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
13389 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13390 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13391 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13392 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13393 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13394 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13395 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13396 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13397 { }
13398};
13399
Kailang Yang60db6b52008-08-26 13:13:00 +020013400/* toggle speaker-output according to the hp-jack state */
13401static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
13402{
13403 unsigned int present;
13404 unsigned char bits;
13405
Wu Fengguang864f92b2009-11-18 12:38:02 +080013406 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yang60db6b52008-08-26 13:13:00 +020013407 bits = present ? AMP_IN_MUTE(0) : 0;
13408 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
13409 AMP_IN_MUTE(0), bits);
13410 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
13411 AMP_IN_MUTE(0), bits);
13412
13413 snd_hda_codec_write(codec, 0x20, 0,
13414 AC_VERB_SET_COEF_INDEX, 0x0c);
13415 snd_hda_codec_write(codec, 0x20, 0,
13416 AC_VERB_SET_PROC_COEF, 0x680);
13417
13418 snd_hda_codec_write(codec, 0x20, 0,
13419 AC_VERB_SET_COEF_INDEX, 0x0c);
13420 snd_hda_codec_write(codec, 0x20, 0,
13421 AC_VERB_SET_PROC_COEF, 0x480);
13422}
13423
Tony Vroon64154832008-11-06 15:08:49 +000013424/* toggle speaker-output according to the hp-jacks state */
13425static void alc269_lifebook_speaker_automute(struct hda_codec *codec)
13426{
13427 unsigned int present;
13428 unsigned char bits;
13429
13430 /* Check laptop headphone socket */
Wu Fengguang864f92b2009-11-18 12:38:02 +080013431 present = snd_hda_jack_detect(codec, 0x15);
Tony Vroon64154832008-11-06 15:08:49 +000013432
13433 /* Check port replicator headphone socket */
Wu Fengguang864f92b2009-11-18 12:38:02 +080013434 present |= snd_hda_jack_detect(codec, 0x1a);
Tony Vroon64154832008-11-06 15:08:49 +000013435
13436 bits = present ? AMP_IN_MUTE(0) : 0;
13437 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
13438 AMP_IN_MUTE(0), bits);
13439 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
13440 AMP_IN_MUTE(0), bits);
13441
13442 snd_hda_codec_write(codec, 0x20, 0,
13443 AC_VERB_SET_COEF_INDEX, 0x0c);
13444 snd_hda_codec_write(codec, 0x20, 0,
13445 AC_VERB_SET_PROC_COEF, 0x680);
13446
13447 snd_hda_codec_write(codec, 0x20, 0,
13448 AC_VERB_SET_COEF_INDEX, 0x0c);
13449 snd_hda_codec_write(codec, 0x20, 0,
13450 AC_VERB_SET_PROC_COEF, 0x480);
13451}
13452
Tony Vroon64154832008-11-06 15:08:49 +000013453static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
13454{
13455 unsigned int present_laptop;
13456 unsigned int present_dock;
13457
Wu Fengguang864f92b2009-11-18 12:38:02 +080013458 present_laptop = snd_hda_jack_detect(codec, 0x18);
13459 present_dock = snd_hda_jack_detect(codec, 0x1b);
Tony Vroon64154832008-11-06 15:08:49 +000013460
13461 /* Laptop mic port overrides dock mic port, design decision */
13462 if (present_dock)
13463 snd_hda_codec_write(codec, 0x23, 0,
13464 AC_VERB_SET_CONNECT_SEL, 0x3);
13465 if (present_laptop)
13466 snd_hda_codec_write(codec, 0x23, 0,
13467 AC_VERB_SET_CONNECT_SEL, 0x0);
13468 if (!present_dock && !present_laptop)
13469 snd_hda_codec_write(codec, 0x23, 0,
13470 AC_VERB_SET_CONNECT_SEL, 0x1);
13471}
13472
Kailang Yang60db6b52008-08-26 13:13:00 +020013473static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
13474 unsigned int res)
13475{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013476 switch (res >> 26) {
13477 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020013478 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013479 break;
13480 case ALC880_MIC_EVENT:
13481 alc_mic_automute(codec);
13482 break;
13483 }
Kailang Yang60db6b52008-08-26 13:13:00 +020013484}
13485
Tony Vroon64154832008-11-06 15:08:49 +000013486static void alc269_lifebook_unsol_event(struct hda_codec *codec,
13487 unsigned int res)
13488{
13489 if ((res >> 26) == ALC880_HP_EVENT)
13490 alc269_lifebook_speaker_automute(codec);
13491 if ((res >> 26) == ALC880_MIC_EVENT)
13492 alc269_lifebook_mic_autoswitch(codec);
13493}
13494
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013495static void alc269_quanta_fl1_setup(struct hda_codec *codec)
13496{
13497 struct alc_spec *spec = codec->spec;
13498 spec->ext_mic.pin = 0x18;
13499 spec->ext_mic.mux_idx = 0;
13500 spec->int_mic.pin = 0x19;
13501 spec->int_mic.mux_idx = 1;
13502 spec->auto_mic = 1;
13503}
13504
Kailang Yang60db6b52008-08-26 13:13:00 +020013505static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
13506{
13507 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013508 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020013509}
13510
Tony Vroon64154832008-11-06 15:08:49 +000013511static void alc269_lifebook_init_hook(struct hda_codec *codec)
13512{
13513 alc269_lifebook_speaker_automute(codec);
13514 alc269_lifebook_mic_autoswitch(codec);
13515}
13516
Kailang Yang84898e82010-02-04 14:16:14 +010013517static struct hda_verb alc269_laptop_dmic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020013518 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13519 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
13520 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
13521 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
13522 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13523 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13524 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13525 {}
13526};
13527
Kailang Yang84898e82010-02-04 14:16:14 +010013528static struct hda_verb alc269_laptop_amic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020013529 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13530 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
13531 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
13532 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
13533 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13534 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13535 {}
13536};
13537
Kailang Yang84898e82010-02-04 14:16:14 +010013538static struct hda_verb alc269vb_laptop_dmic_init_verbs[] = {
13539 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
13540 {0x22, AC_VERB_SET_CONNECT_SEL, 0x06},
13541 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
13542 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
13543 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13544 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13545 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13546 {}
13547};
13548
13549static struct hda_verb alc269vb_laptop_amic_init_verbs[] = {
13550 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
13551 {0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
13552 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
13553 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
13554 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13555 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13556 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13557 {}
13558};
13559
Kailang Yang60db6b52008-08-26 13:13:00 +020013560/* toggle speaker-output according to the hp-jack state */
13561static void alc269_speaker_automute(struct hda_codec *codec)
13562{
Kailang Yangebb83ee2009-12-17 12:23:00 +010013563 struct alc_spec *spec = codec->spec;
13564 unsigned int nid = spec->autocfg.hp_pins[0];
Kailang Yang60db6b52008-08-26 13:13:00 +020013565 unsigned int present;
13566 unsigned char bits;
13567
Kailang Yangebb83ee2009-12-17 12:23:00 +010013568 present = snd_hda_jack_detect(codec, nid);
Kailang Yang60db6b52008-08-26 13:13:00 +020013569 bits = present ? AMP_IN_MUTE(0) : 0;
13570 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
13571 AMP_IN_MUTE(0), bits);
13572 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
13573 AMP_IN_MUTE(0), bits);
13574}
13575
Kailang Yang60db6b52008-08-26 13:13:00 +020013576/* unsolicited event for HP jack sensing */
Kailang Yang84898e82010-02-04 14:16:14 +010013577static void alc269_laptop_unsol_event(struct hda_codec *codec,
Kailang Yang60db6b52008-08-26 13:13:00 +020013578 unsigned int res)
13579{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013580 switch (res >> 26) {
13581 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020013582 alc269_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013583 break;
13584 case ALC880_MIC_EVENT:
13585 alc_mic_automute(codec);
13586 break;
13587 }
Kailang Yang60db6b52008-08-26 13:13:00 +020013588}
13589
Kailang Yang84898e82010-02-04 14:16:14 +010013590static void alc269_laptop_dmic_setup(struct hda_codec *codec)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013591{
13592 struct alc_spec *spec = codec->spec;
13593 spec->ext_mic.pin = 0x18;
13594 spec->ext_mic.mux_idx = 0;
13595 spec->int_mic.pin = 0x12;
13596 spec->int_mic.mux_idx = 5;
13597 spec->auto_mic = 1;
13598}
13599
Kailang Yang84898e82010-02-04 14:16:14 +010013600static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
13601{
13602 struct alc_spec *spec = codec->spec;
13603 spec->ext_mic.pin = 0x18;
13604 spec->ext_mic.mux_idx = 0;
13605 spec->int_mic.pin = 0x12;
13606 spec->int_mic.mux_idx = 6;
13607 spec->auto_mic = 1;
13608}
13609
13610static void alc269_laptop_amic_setup(struct hda_codec *codec)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013611{
13612 struct alc_spec *spec = codec->spec;
13613 spec->ext_mic.pin = 0x18;
13614 spec->ext_mic.mux_idx = 0;
13615 spec->int_mic.pin = 0x19;
13616 spec->int_mic.mux_idx = 1;
13617 spec->auto_mic = 1;
13618}
13619
Kailang Yang84898e82010-02-04 14:16:14 +010013620static void alc269_laptop_inithook(struct hda_codec *codec)
Kailang Yang60db6b52008-08-26 13:13:00 +020013621{
13622 alc269_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013623 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020013624}
13625
Kailang Yangf6a92242007-12-13 16:52:54 +010013626/*
13627 * generic initialization of ADC, input mixers and output mixers
13628 */
13629static struct hda_verb alc269_init_verbs[] = {
13630 /*
13631 * Unmute ADC0 and set the default input to mic-in
13632 */
Kailang Yang84898e82010-02-04 14:16:14 +010013633 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010013634
13635 /*
Kailang Yang84898e82010-02-04 14:16:14 +010013636 * Set up output mixers (0x02 - 0x03)
Kailang Yangf6a92242007-12-13 16:52:54 +010013637 */
13638 /* set vol=0 to output mixers */
13639 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13640 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13641
13642 /* set up input amps for analog loopback */
13643 /* Amp Indices: DAC = 0, mixer = 1 */
13644 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13645 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13646 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13647 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13648 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13649 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13650
13651 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13652 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13653 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13654 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13655 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13656 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13657 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13658
13659 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13660 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf6a92242007-12-13 16:52:54 +010013661
Kailang Yang84898e82010-02-04 14:16:14 +010013662 /* FIXME: use Mux-type input source selection */
Kailang Yangf6a92242007-12-13 16:52:54 +010013663 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
13664 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang84898e82010-02-04 14:16:14 +010013665 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangf6a92242007-12-13 16:52:54 +010013666
13667 /* set EAPD */
13668 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yang84898e82010-02-04 14:16:14 +010013669 { }
13670};
13671
13672static struct hda_verb alc269vb_init_verbs[] = {
13673 /*
13674 * Unmute ADC0 and set the default input to mic-in
13675 */
13676 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13677
13678 /*
13679 * Set up output mixers (0x02 - 0x03)
13680 */
13681 /* set vol=0 to output mixers */
13682 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13683 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13684
13685 /* set up input amps for analog loopback */
13686 /* Amp Indices: DAC = 0, mixer = 1 */
13687 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13688 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13689 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13690 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13691 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13692 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13693
13694 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13695 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13696 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13697 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13698 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13699 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13700 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13701
13702 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13703 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13704
13705 /* FIXME: use Mux-type input source selection */
13706 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
13707 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
13708 {0x22, AC_VERB_SET_CONNECT_SEL, 0x00},
13709
13710 /* set EAPD */
13711 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yangf6a92242007-12-13 16:52:54 +010013712 { }
13713};
13714
Takashi Iwai9d0b71b2009-08-24 14:10:30 +020013715#define alc269_auto_create_multi_out_ctls \
13716 alc268_auto_create_multi_out_ctls
Takashi Iwai05f5f472009-08-25 13:10:18 +020013717#define alc269_auto_create_input_ctls \
13718 alc268_auto_create_input_ctls
Kailang Yangf6a92242007-12-13 16:52:54 +010013719
13720#ifdef CONFIG_SND_HDA_POWER_SAVE
13721#define alc269_loopbacks alc880_loopbacks
13722#endif
13723
Sasha Alexandrdef319f2009-06-16 16:00:15 -040013724/* pcm configuration: identical with ALC880 */
Kailang Yangf6a92242007-12-13 16:52:54 +010013725#define alc269_pcm_analog_playback alc880_pcm_analog_playback
13726#define alc269_pcm_analog_capture alc880_pcm_analog_capture
13727#define alc269_pcm_digital_playback alc880_pcm_digital_playback
13728#define alc269_pcm_digital_capture alc880_pcm_digital_capture
13729
Takashi Iwaif03d3112009-03-05 14:18:16 +010013730static struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
13731 .substreams = 1,
13732 .channels_min = 2,
13733 .channels_max = 8,
13734 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
13735 /* NID is set in alc_build_pcms */
13736 .ops = {
13737 .open = alc880_playback_pcm_open,
13738 .prepare = alc880_playback_pcm_prepare,
13739 .cleanup = alc880_playback_pcm_cleanup
13740 },
13741};
13742
13743static struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
13744 .substreams = 1,
13745 .channels_min = 2,
13746 .channels_max = 2,
13747 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
13748 /* NID is set in alc_build_pcms */
13749};
13750
Kailang Yangf6a92242007-12-13 16:52:54 +010013751/*
13752 * BIOS auto configuration
13753 */
13754static int alc269_parse_auto_config(struct hda_codec *codec)
13755{
13756 struct alc_spec *spec = codec->spec;
Takashi Iwaicfb9fb52009-02-06 17:34:03 +010013757 int err;
Kailang Yangf6a92242007-12-13 16:52:54 +010013758 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
Kailang Yang84898e82010-02-04 14:16:14 +010013759 hda_nid_t real_capsrc_nids;
Kailang Yangf6a92242007-12-13 16:52:54 +010013760
13761 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13762 alc269_ignore);
13763 if (err < 0)
13764 return err;
13765
13766 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
13767 if (err < 0)
13768 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020013769 err = alc269_auto_create_input_ctls(codec, &spec->autocfg);
Kailang Yangf6a92242007-12-13 16:52:54 +010013770 if (err < 0)
13771 return err;
13772
13773 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
13774
Takashi Iwai0852d7a2009-02-11 11:35:15 +010013775 if (spec->autocfg.dig_outs)
Kailang Yangf6a92242007-12-13 16:52:54 +010013776 spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
13777
Takashi Iwai603c4012008-07-30 15:01:44 +020013778 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013779 add_mixer(spec, spec->kctls.list);
Kailang Yangf6a92242007-12-13 16:52:54 +010013780
Kailang Yang84898e82010-02-04 14:16:14 +010013781 if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010) {
13782 add_verb(spec, alc269vb_init_verbs);
13783 real_capsrc_nids = alc269vb_capsrc_nids[0];
13784 alc_ssid_check(codec, 0x21, 0x1b, 0x14);
13785 } else {
13786 add_verb(spec, alc269_init_verbs);
13787 real_capsrc_nids = alc269_capsrc_nids[0];
13788 alc_ssid_check(codec, 0x15, 0x1b, 0x14);
13789 }
13790
Kailang Yangf6a92242007-12-13 16:52:54 +010013791 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020013792 spec->input_mux = &spec->private_imux[0];
Takashi Iwaie01bf502008-08-21 16:25:07 +020013793 /* set default input source */
Kailang Yang84898e82010-02-04 14:16:14 +010013794 snd_hda_codec_write_cache(codec, real_capsrc_nids,
Takashi Iwaie01bf502008-08-21 16:25:07 +020013795 0, AC_VERB_SET_CONNECT_SEL,
13796 spec->input_mux->items[0].index);
Kailang Yangf6a92242007-12-13 16:52:54 +010013797
13798 err = alc_auto_add_mic_boost(codec);
13799 if (err < 0)
13800 return err;
13801
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013802 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020013803 set_capture_mixer(codec);
Kailang Yangf53281e2008-07-18 12:36:43 +020013804
Kailang Yangf6a92242007-12-13 16:52:54 +010013805 return 1;
13806}
13807
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013808#define alc269_auto_init_multi_out alc268_auto_init_multi_out
13809#define alc269_auto_init_hp_out alc268_auto_init_hp_out
Kailang Yangf6a92242007-12-13 16:52:54 +010013810#define alc269_auto_init_analog_input alc882_auto_init_analog_input
13811
13812
13813/* init callback for auto-configuration model -- overriding the default init */
13814static void alc269_auto_init(struct hda_codec *codec)
13815{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013816 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010013817 alc269_auto_init_multi_out(codec);
13818 alc269_auto_init_hp_out(codec);
13819 alc269_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013820 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020013821 alc_inithook(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010013822}
13823
13824/*
13825 * configuration and preset
13826 */
13827static const char *alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020013828 [ALC269_BASIC] = "basic",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020013829 [ALC269_QUANTA_FL1] = "quanta",
Kailang Yang84898e82010-02-04 14:16:14 +010013830 [ALC269_AMIC] = "laptop-amic",
13831 [ALC269_DMIC] = "laptop-dmic",
Tony Vroon64154832008-11-06 15:08:49 +000013832 [ALC269_FUJITSU] = "fujitsu",
Takashi Iwai3d3792c2009-09-11 07:50:47 +020013833 [ALC269_LIFEBOOK] = "lifebook",
13834 [ALC269_AUTO] = "auto",
Kailang Yangf6a92242007-12-13 16:52:54 +010013835};
13836
13837static struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020013838 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangf53281e2008-07-18 12:36:43 +020013839 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
Kailang Yang84898e82010-02-04 14:16:14 +010013840 ALC269_AMIC),
13841 SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC),
13842 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC),
13843 SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC),
13844 SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC),
13845 SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC),
13846 SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC),
13847 SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC),
13848 SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC),
13849 SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC),
13850 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82Jv", ALC269_AMIC),
13851 SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC),
13852 SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC),
13853 SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC),
13854 SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC),
13855 SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC),
13856 SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC),
13857 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC),
13858 SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC),
13859 SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC),
13860 SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC),
13861 SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC),
13862 SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC),
13863 SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC),
13864 SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC),
13865 SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC),
13866 SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC),
13867 SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC),
13868 SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC),
13869 SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC),
13870 SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC),
13871 SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC),
13872 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC),
13873 SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC),
13874 SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC),
13875 SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC),
13876 SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC),
Kailang Yangf53281e2008-07-18 12:36:43 +020013877 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
Kailang Yang84898e82010-02-04 14:16:14 +010013878 ALC269_DMIC),
Kailang Yang60db6b52008-08-26 13:13:00 +020013879 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
Kailang Yang84898e82010-02-04 14:16:14 +010013880 ALC269_DMIC),
13881 SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC),
13882 SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC),
Takashi Iwai26f5df22008-11-03 17:39:46 +010013883 SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
Tony Vroon64154832008-11-06 15:08:49 +000013884 SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
Kailang Yangf6a92242007-12-13 16:52:54 +010013885 {}
13886};
13887
13888static struct alc_config_preset alc269_presets[] = {
13889 [ALC269_BASIC] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010013890 .mixers = { alc269_base_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010013891 .init_verbs = { alc269_init_verbs },
13892 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13893 .dac_nids = alc269_dac_nids,
13894 .hp_nid = 0x03,
13895 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13896 .channel_mode = alc269_modes,
13897 .input_mux = &alc269_capture_source,
13898 },
Kailang Yang60db6b52008-08-26 13:13:00 +020013899 [ALC269_QUANTA_FL1] = {
13900 .mixers = { alc269_quanta_fl1_mixer },
13901 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
13902 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13903 .dac_nids = alc269_dac_nids,
13904 .hp_nid = 0x03,
13905 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13906 .channel_mode = alc269_modes,
13907 .input_mux = &alc269_capture_source,
13908 .unsol_event = alc269_quanta_fl1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013909 .setup = alc269_quanta_fl1_setup,
Kailang Yang60db6b52008-08-26 13:13:00 +020013910 .init_hook = alc269_quanta_fl1_init_hook,
13911 },
Kailang Yang84898e82010-02-04 14:16:14 +010013912 [ALC269_AMIC] = {
13913 .mixers = { alc269_laptop_mixer },
13914 .cap_mixer = alc269_laptop_analog_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020013915 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010013916 alc269_laptop_amic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020013917 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13918 .dac_nids = alc269_dac_nids,
13919 .hp_nid = 0x03,
13920 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13921 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010013922 .unsol_event = alc269_laptop_unsol_event,
13923 .setup = alc269_laptop_amic_setup,
13924 .init_hook = alc269_laptop_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020013925 },
Kailang Yang84898e82010-02-04 14:16:14 +010013926 [ALC269_DMIC] = {
13927 .mixers = { alc269_laptop_mixer },
13928 .cap_mixer = alc269_laptop_digital_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020013929 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010013930 alc269_laptop_dmic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020013931 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13932 .dac_nids = alc269_dac_nids,
13933 .hp_nid = 0x03,
13934 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13935 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010013936 .unsol_event = alc269_laptop_unsol_event,
13937 .setup = alc269_laptop_dmic_setup,
13938 .init_hook = alc269_laptop_inithook,
13939 },
13940 [ALC269VB_AMIC] = {
13941 .mixers = { alc269vb_laptop_mixer },
13942 .cap_mixer = alc269vb_laptop_analog_capture_mixer,
13943 .init_verbs = { alc269vb_init_verbs,
13944 alc269vb_laptop_amic_init_verbs },
13945 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13946 .dac_nids = alc269_dac_nids,
13947 .hp_nid = 0x03,
13948 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13949 .channel_mode = alc269_modes,
13950 .unsol_event = alc269_laptop_unsol_event,
13951 .setup = alc269_laptop_amic_setup,
13952 .init_hook = alc269_laptop_inithook,
13953 },
13954 [ALC269VB_DMIC] = {
13955 .mixers = { alc269vb_laptop_mixer },
13956 .cap_mixer = alc269vb_laptop_digital_capture_mixer,
13957 .init_verbs = { alc269vb_init_verbs,
13958 alc269vb_laptop_dmic_init_verbs },
13959 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13960 .dac_nids = alc269_dac_nids,
13961 .hp_nid = 0x03,
13962 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13963 .channel_mode = alc269_modes,
13964 .unsol_event = alc269_laptop_unsol_event,
13965 .setup = alc269vb_laptop_dmic_setup,
13966 .init_hook = alc269_laptop_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020013967 },
Takashi Iwai26f5df22008-11-03 17:39:46 +010013968 [ALC269_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010013969 .mixers = { alc269_fujitsu_mixer },
Kailang Yang84898e82010-02-04 14:16:14 +010013970 .cap_mixer = alc269_laptop_digital_capture_mixer,
Takashi Iwai26f5df22008-11-03 17:39:46 +010013971 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010013972 alc269_laptop_dmic_init_verbs },
Takashi Iwai26f5df22008-11-03 17:39:46 +010013973 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13974 .dac_nids = alc269_dac_nids,
13975 .hp_nid = 0x03,
13976 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13977 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010013978 .unsol_event = alc269_laptop_unsol_event,
13979 .setup = alc269_laptop_dmic_setup,
13980 .init_hook = alc269_laptop_inithook,
Takashi Iwai26f5df22008-11-03 17:39:46 +010013981 },
Tony Vroon64154832008-11-06 15:08:49 +000013982 [ALC269_LIFEBOOK] = {
13983 .mixers = { alc269_lifebook_mixer },
13984 .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
13985 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13986 .dac_nids = alc269_dac_nids,
13987 .hp_nid = 0x03,
13988 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13989 .channel_mode = alc269_modes,
13990 .input_mux = &alc269_capture_source,
13991 .unsol_event = alc269_lifebook_unsol_event,
13992 .init_hook = alc269_lifebook_init_hook,
13993 },
Kailang Yangf6a92242007-12-13 16:52:54 +010013994};
13995
13996static int patch_alc269(struct hda_codec *codec)
13997{
13998 struct alc_spec *spec;
13999 int board_config;
14000 int err;
Kailang Yang84898e82010-02-04 14:16:14 +010014001 int is_alc269vb = 0;
Kailang Yangf6a92242007-12-13 16:52:54 +010014002
14003 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
14004 if (spec == NULL)
14005 return -ENOMEM;
14006
14007 codec->spec = spec;
14008
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020014009 alc_fix_pll_init(codec, 0x20, 0x04, 15);
14010
Kailang Yang274693f2009-12-03 10:07:50 +010014011 if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){
14012 kfree(codec->chip_name);
14013 codec->chip_name = kstrdup("ALC259", GFP_KERNEL);
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010014014 if (!codec->chip_name) {
14015 alc_free(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010014016 return -ENOMEM;
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010014017 }
Kailang Yang84898e82010-02-04 14:16:14 +010014018 is_alc269vb = 1;
Kailang Yang274693f2009-12-03 10:07:50 +010014019 }
14020
Kailang Yangf6a92242007-12-13 16:52:54 +010014021 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
14022 alc269_models,
14023 alc269_cfg_tbl);
14024
14025 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020014026 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
14027 codec->chip_name);
Kailang Yangf6a92242007-12-13 16:52:54 +010014028 board_config = ALC269_AUTO;
14029 }
14030
14031 if (board_config == ALC269_AUTO) {
14032 /* automatic parse from the BIOS config */
14033 err = alc269_parse_auto_config(codec);
14034 if (err < 0) {
14035 alc_free(codec);
14036 return err;
14037 } else if (!err) {
14038 printk(KERN_INFO
14039 "hda_codec: Cannot set up configuration "
14040 "from BIOS. Using base mode...\n");
14041 board_config = ALC269_BASIC;
14042 }
14043 }
14044
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090014045 err = snd_hda_attach_beep_device(codec, 0x1);
14046 if (err < 0) {
14047 alc_free(codec);
14048 return err;
14049 }
14050
Kailang Yangf6a92242007-12-13 16:52:54 +010014051 if (board_config != ALC269_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020014052 setup_preset(codec, &alc269_presets[board_config]);
Kailang Yangf6a92242007-12-13 16:52:54 +010014053
Kailang Yang84898e82010-02-04 14:16:14 +010014054 if (board_config == ALC269_QUANTA_FL1) {
Takashi Iwaif03d3112009-03-05 14:18:16 +010014055 /* Due to a hardware problem on Lenovo Ideadpad, we need to
14056 * fix the sample rate of analog I/O to 44.1kHz
14057 */
14058 spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
14059 spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
14060 } else {
14061 spec->stream_analog_playback = &alc269_pcm_analog_playback;
14062 spec->stream_analog_capture = &alc269_pcm_analog_capture;
14063 }
Kailang Yangf6a92242007-12-13 16:52:54 +010014064 spec->stream_digital_playback = &alc269_pcm_digital_playback;
14065 spec->stream_digital_capture = &alc269_pcm_digital_capture;
14066
Kailang Yang84898e82010-02-04 14:16:14 +010014067 if (!is_alc269vb) {
14068 spec->adc_nids = alc269_adc_nids;
14069 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
14070 spec->capsrc_nids = alc269_capsrc_nids;
14071 } else {
14072 spec->adc_nids = alc269vb_adc_nids;
14073 spec->num_adc_nids = ARRAY_SIZE(alc269vb_adc_nids);
14074 spec->capsrc_nids = alc269vb_capsrc_nids;
14075 }
14076
Takashi Iwaif9e336f2008-10-31 16:37:07 +010014077 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020014078 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010014079 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Kailang Yangf6a92242007-12-13 16:52:54 +010014080
Takashi Iwai100d5eb2009-08-10 11:55:51 +020014081 spec->vmaster_nid = 0x02;
14082
Kailang Yangf6a92242007-12-13 16:52:54 +010014083 codec->patch_ops = alc_patch_ops;
14084 if (board_config == ALC269_AUTO)
14085 spec->init_hook = alc269_auto_init;
14086#ifdef CONFIG_SND_HDA_POWER_SAVE
14087 if (!spec->loopback.amplist)
14088 spec->loopback.amplist = alc269_loopbacks;
14089#endif
14090
14091 return 0;
14092}
14093
14094/*
Kailang Yangdf694da2005-12-05 19:42:22 +010014095 * ALC861 channel source setting (2/6 channel selection for 3-stack)
14096 */
14097
14098/*
14099 * set the path ways for 2 channel output
14100 * need to set the codec line out and mic 1 pin widgets to inputs
14101 */
14102static struct hda_verb alc861_threestack_ch2_init[] = {
14103 /* set pin widget 1Ah (line in) for input */
14104 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014105 /* set pin widget 18h (mic1/2) for input, for mic also enable
14106 * the vref
14107 */
Kailang Yangdf694da2005-12-05 19:42:22 +010014108 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14109
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014110 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
14111#if 0
14112 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
14113 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
14114#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010014115 { } /* end */
14116};
14117/*
14118 * 6ch mode
14119 * need to set the codec line out and mic 1 pin widgets to outputs
14120 */
14121static struct hda_verb alc861_threestack_ch6_init[] = {
14122 /* set pin widget 1Ah (line in) for output (Back Surround)*/
14123 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14124 /* set pin widget 18h (mic1) for output (CLFE)*/
14125 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14126
14127 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014128 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010014129
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014130 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
14131#if 0
14132 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
14133 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
14134#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010014135 { } /* end */
14136};
14137
14138static struct hda_channel_mode alc861_threestack_modes[2] = {
14139 { 2, alc861_threestack_ch2_init },
14140 { 6, alc861_threestack_ch6_init },
14141};
Takashi Iwai22309c32006-08-09 16:57:28 +020014142/* Set mic1 as input and unmute the mixer */
14143static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
14144 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14145 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
14146 { } /* end */
14147};
14148/* Set mic1 as output and mute mixer */
14149static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
14150 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14151 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
14152 { } /* end */
14153};
14154
14155static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
14156 { 2, alc861_uniwill_m31_ch2_init },
14157 { 4, alc861_uniwill_m31_ch4_init },
14158};
Kailang Yangdf694da2005-12-05 19:42:22 +010014159
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014160/* Set mic1 and line-in as input and unmute the mixer */
14161static struct hda_verb alc861_asus_ch2_init[] = {
14162 /* set pin widget 1Ah (line in) for input */
14163 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014164 /* set pin widget 18h (mic1/2) for input, for mic also enable
14165 * the vref
14166 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014167 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14168
14169 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
14170#if 0
14171 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
14172 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
14173#endif
14174 { } /* end */
14175};
14176/* Set mic1 nad line-in as output and mute mixer */
14177static struct hda_verb alc861_asus_ch6_init[] = {
14178 /* set pin widget 1Ah (line in) for output (Back Surround)*/
14179 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14180 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
14181 /* set pin widget 18h (mic1) for output (CLFE)*/
14182 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14183 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
14184 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
14185 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
14186
14187 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
14188#if 0
14189 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
14190 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
14191#endif
14192 { } /* end */
14193};
14194
14195static struct hda_channel_mode alc861_asus_modes[2] = {
14196 { 2, alc861_asus_ch2_init },
14197 { 6, alc861_asus_ch6_init },
14198};
14199
Kailang Yangdf694da2005-12-05 19:42:22 +010014200/* patch-ALC861 */
14201
14202static struct snd_kcontrol_new alc861_base_mixer[] = {
14203 /* output mixer control */
14204 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14205 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14206 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14207 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14208 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
14209
14210 /*Input mixer control */
14211 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14212 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
14213 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14214 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14215 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14216 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14217 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14218 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14219 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
14220 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014221
Kailang Yangdf694da2005-12-05 19:42:22 +010014222 { } /* end */
14223};
14224
14225static struct snd_kcontrol_new alc861_3ST_mixer[] = {
14226 /* output mixer control */
14227 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14228 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14229 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14230 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14231 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
14232
14233 /* Input mixer control */
14234 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14235 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
14236 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14237 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14238 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14239 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14240 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14241 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14242 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
14243 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014244
Kailang Yangdf694da2005-12-05 19:42:22 +010014245 {
14246 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14247 .name = "Channel Mode",
14248 .info = alc_ch_mode_info,
14249 .get = alc_ch_mode_get,
14250 .put = alc_ch_mode_put,
14251 .private_value = ARRAY_SIZE(alc861_threestack_modes),
14252 },
14253 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014254};
14255
Takashi Iwaid1d985f2006-11-23 19:27:12 +010014256static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014257 /* output mixer control */
14258 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14259 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14260 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020014261
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014262 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014263};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014264
Takashi Iwai22309c32006-08-09 16:57:28 +020014265static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
14266 /* output mixer control */
14267 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14268 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14269 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14270 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14271 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
14272
14273 /* Input mixer control */
14274 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14275 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
14276 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14277 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14278 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14279 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14280 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14281 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14282 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
14283 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014284
Takashi Iwai22309c32006-08-09 16:57:28 +020014285 {
14286 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14287 .name = "Channel Mode",
14288 .info = alc_ch_mode_info,
14289 .get = alc_ch_mode_get,
14290 .put = alc_ch_mode_put,
14291 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
14292 },
14293 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014294};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014295
14296static struct snd_kcontrol_new alc861_asus_mixer[] = {
14297 /* output mixer control */
14298 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14299 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14300 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14301 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14302 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
14303
14304 /* Input mixer control */
14305 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14306 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
14307 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14308 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14309 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14310 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14311 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14312 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14313 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014314 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
14315
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014316 {
14317 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14318 .name = "Channel Mode",
14319 .info = alc_ch_mode_info,
14320 .get = alc_ch_mode_get,
14321 .put = alc_ch_mode_put,
14322 .private_value = ARRAY_SIZE(alc861_asus_modes),
14323 },
14324 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014325};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014326
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014327/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010014328static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014329 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14330 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014331 { }
14332};
14333
Kailang Yangdf694da2005-12-05 19:42:22 +010014334/*
14335 * generic initialization of ADC, input mixers and output mixers
14336 */
14337static struct hda_verb alc861_base_init_verbs[] = {
14338 /*
14339 * Unmute ADC0 and set the default input to mic-in
14340 */
14341 /* port-A for surround (rear panel) */
14342 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14343 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
14344 /* port-B for mic-in (rear panel) with vref */
14345 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14346 /* port-C for line-in (rear panel) */
14347 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14348 /* port-D for Front */
14349 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14350 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
14351 /* port-E for HP out (front panel) */
14352 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
14353 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010014354 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010014355 /* port-F for mic-in (front panel) with vref */
14356 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14357 /* port-G for CLFE (rear panel) */
14358 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14359 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
14360 /* port-H for side (rear panel) */
14361 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14362 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
14363 /* CD-in */
14364 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14365 /* route front mic to ADC1*/
14366 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
14367 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014368
Kailang Yangdf694da2005-12-05 19:42:22 +010014369 /* Unmute DAC0~3 & spdif out*/
14370 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14371 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14372 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14373 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14374 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020014375
Kailang Yangdf694da2005-12-05 19:42:22 +010014376 /* Unmute Mixer 14 (mic) 1c (Line in)*/
14377 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14378 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14379 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14380 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014381
Kailang Yangdf694da2005-12-05 19:42:22 +010014382 /* Unmute Stereo Mixer 15 */
14383 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14384 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14385 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014386 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010014387
14388 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14389 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14390 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14391 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14392 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14393 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14394 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14395 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014396 /* hp used DAC 3 (Front) */
14397 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010014398 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
14399
14400 { }
14401};
14402
14403static struct hda_verb alc861_threestack_init_verbs[] = {
14404 /*
14405 * Unmute ADC0 and set the default input to mic-in
14406 */
14407 /* port-A for surround (rear panel) */
14408 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14409 /* port-B for mic-in (rear panel) with vref */
14410 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14411 /* port-C for line-in (rear panel) */
14412 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14413 /* port-D for Front */
14414 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14415 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
14416 /* port-E for HP out (front panel) */
14417 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
14418 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010014419 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010014420 /* port-F for mic-in (front panel) with vref */
14421 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14422 /* port-G for CLFE (rear panel) */
14423 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14424 /* port-H for side (rear panel) */
14425 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14426 /* CD-in */
14427 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14428 /* route front mic to ADC1*/
14429 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
14430 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14431 /* Unmute DAC0~3 & spdif out*/
14432 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14433 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14434 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14435 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14436 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020014437
Kailang Yangdf694da2005-12-05 19:42:22 +010014438 /* Unmute Mixer 14 (mic) 1c (Line in)*/
14439 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14440 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14441 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14442 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014443
Kailang Yangdf694da2005-12-05 19:42:22 +010014444 /* Unmute Stereo Mixer 15 */
14445 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14446 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14447 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014448 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010014449
14450 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14451 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14452 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14453 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14454 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14455 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14456 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14457 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014458 /* hp used DAC 3 (Front) */
14459 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010014460 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
14461 { }
14462};
Takashi Iwai22309c32006-08-09 16:57:28 +020014463
14464static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
14465 /*
14466 * Unmute ADC0 and set the default input to mic-in
14467 */
14468 /* port-A for surround (rear panel) */
14469 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14470 /* port-B for mic-in (rear panel) with vref */
14471 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14472 /* port-C for line-in (rear panel) */
14473 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14474 /* port-D for Front */
14475 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14476 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
14477 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014478 /* this has to be set to VREF80 */
14479 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020014480 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010014481 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020014482 /* port-F for mic-in (front panel) with vref */
14483 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14484 /* port-G for CLFE (rear panel) */
14485 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14486 /* port-H for side (rear panel) */
14487 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14488 /* CD-in */
14489 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14490 /* route front mic to ADC1*/
14491 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
14492 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14493 /* Unmute DAC0~3 & spdif out*/
14494 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14495 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14496 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14497 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14498 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020014499
Takashi Iwai22309c32006-08-09 16:57:28 +020014500 /* Unmute Mixer 14 (mic) 1c (Line in)*/
14501 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14502 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14503 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14504 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014505
Takashi Iwai22309c32006-08-09 16:57:28 +020014506 /* Unmute Stereo Mixer 15 */
14507 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14508 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14509 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014510 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020014511
14512 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14513 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14514 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14515 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14516 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14517 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14518 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14519 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014520 /* hp used DAC 3 (Front) */
14521 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020014522 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
14523 { }
14524};
14525
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014526static struct hda_verb alc861_asus_init_verbs[] = {
14527 /*
14528 * Unmute ADC0 and set the default input to mic-in
14529 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014530 /* port-A for surround (rear panel)
14531 * according to codec#0 this is the HP jack
14532 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014533 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
14534 /* route front PCM to HP */
14535 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
14536 /* port-B for mic-in (rear panel) with vref */
14537 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14538 /* port-C for line-in (rear panel) */
14539 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14540 /* port-D for Front */
14541 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14542 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
14543 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014544 /* this has to be set to VREF80 */
14545 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014546 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010014547 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014548 /* port-F for mic-in (front panel) with vref */
14549 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14550 /* port-G for CLFE (rear panel) */
14551 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14552 /* port-H for side (rear panel) */
14553 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14554 /* CD-in */
14555 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14556 /* route front mic to ADC1*/
14557 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
14558 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14559 /* Unmute DAC0~3 & spdif out*/
14560 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14561 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14562 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14563 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14564 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14565 /* Unmute Mixer 14 (mic) 1c (Line in)*/
14566 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14567 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14568 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14569 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014570
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014571 /* Unmute Stereo Mixer 15 */
14572 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14573 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14574 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014575 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014576
14577 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14578 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14579 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14580 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14581 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14582 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14583 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14584 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014585 /* hp used DAC 3 (Front) */
14586 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014587 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
14588 { }
14589};
14590
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014591/* additional init verbs for ASUS laptops */
14592static struct hda_verb alc861_asus_laptop_init_verbs[] = {
14593 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
14594 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
14595 { }
14596};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014597
Kailang Yangdf694da2005-12-05 19:42:22 +010014598/*
14599 * generic initialization of ADC, input mixers and output mixers
14600 */
14601static struct hda_verb alc861_auto_init_verbs[] = {
14602 /*
14603 * Unmute ADC0 and set the default input to mic-in
14604 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014605 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010014606 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014607
Kailang Yangdf694da2005-12-05 19:42:22 +010014608 /* Unmute DAC0~3 & spdif out*/
14609 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14610 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14611 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14612 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14613 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020014614
Kailang Yangdf694da2005-12-05 19:42:22 +010014615 /* Unmute Mixer 14 (mic) 1c (Line in)*/
14616 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14617 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14618 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14619 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014620
Kailang Yangdf694da2005-12-05 19:42:22 +010014621 /* Unmute Stereo Mixer 15 */
14622 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14623 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14624 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
14625 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
14626
Takashi Iwai1c209302009-07-22 15:17:45 +020014627 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14628 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14629 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14630 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14631 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14632 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14633 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14634 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangdf694da2005-12-05 19:42:22 +010014635
14636 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14637 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020014638 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
14639 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010014640 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14641 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020014642 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
14643 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010014644
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014645 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010014646
14647 { }
14648};
14649
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014650static struct hda_verb alc861_toshiba_init_verbs[] = {
14651 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014652
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014653 { }
14654};
14655
14656/* toggle speaker-output according to the hp-jack state */
14657static void alc861_toshiba_automute(struct hda_codec *codec)
14658{
Wu Fengguang864f92b2009-11-18 12:38:02 +080014659 unsigned int present = snd_hda_jack_detect(codec, 0x0f);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014660
Takashi Iwai47fd8302007-08-10 17:11:07 +020014661 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
14662 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
14663 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
14664 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014665}
14666
14667static void alc861_toshiba_unsol_event(struct hda_codec *codec,
14668 unsigned int res)
14669{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014670 if ((res >> 26) == ALC880_HP_EVENT)
14671 alc861_toshiba_automute(codec);
14672}
14673
Sasha Alexandrdef319f2009-06-16 16:00:15 -040014674/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010014675#define alc861_pcm_analog_playback alc880_pcm_analog_playback
14676#define alc861_pcm_analog_capture alc880_pcm_analog_capture
14677#define alc861_pcm_digital_playback alc880_pcm_digital_playback
14678#define alc861_pcm_digital_capture alc880_pcm_digital_capture
14679
14680
14681#define ALC861_DIGOUT_NID 0x07
14682
14683static struct hda_channel_mode alc861_8ch_modes[1] = {
14684 { 8, NULL }
14685};
14686
14687static hda_nid_t alc861_dac_nids[4] = {
14688 /* front, surround, clfe, side */
14689 0x03, 0x06, 0x05, 0x04
14690};
14691
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014692static hda_nid_t alc660_dac_nids[3] = {
14693 /* front, clfe, surround */
14694 0x03, 0x05, 0x06
14695};
14696
Kailang Yangdf694da2005-12-05 19:42:22 +010014697static hda_nid_t alc861_adc_nids[1] = {
14698 /* ADC0-2 */
14699 0x08,
14700};
14701
14702static struct hda_input_mux alc861_capture_source = {
14703 .num_items = 5,
14704 .items = {
14705 { "Mic", 0x0 },
14706 { "Front Mic", 0x3 },
14707 { "Line", 0x1 },
14708 { "CD", 0x4 },
14709 { "Mixer", 0x5 },
14710 },
14711};
14712
Takashi Iwai1c209302009-07-22 15:17:45 +020014713static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
14714{
14715 struct alc_spec *spec = codec->spec;
14716 hda_nid_t mix, srcs[5];
14717 int i, j, num;
14718
14719 if (snd_hda_get_connections(codec, pin, &mix, 1) != 1)
14720 return 0;
14721 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
14722 if (num < 0)
14723 return 0;
14724 for (i = 0; i < num; i++) {
14725 unsigned int type;
Takashi Iwaia22d5432009-07-27 12:54:26 +020014726 type = get_wcaps_type(get_wcaps(codec, srcs[i]));
Takashi Iwai1c209302009-07-22 15:17:45 +020014727 if (type != AC_WID_AUD_OUT)
14728 continue;
14729 for (j = 0; j < spec->multiout.num_dacs; j++)
14730 if (spec->multiout.dac_nids[j] == srcs[i])
14731 break;
14732 if (j >= spec->multiout.num_dacs)
14733 return srcs[i];
14734 }
14735 return 0;
14736}
14737
Kailang Yangdf694da2005-12-05 19:42:22 +010014738/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwai1c209302009-07-22 15:17:45 +020014739static int alc861_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014740 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010014741{
Takashi Iwai1c209302009-07-22 15:17:45 +020014742 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010014743 int i;
Takashi Iwai1c209302009-07-22 15:17:45 +020014744 hda_nid_t nid, dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010014745
14746 spec->multiout.dac_nids = spec->private_dac_nids;
14747 for (i = 0; i < cfg->line_outs; i++) {
14748 nid = cfg->line_out_pins[i];
Takashi Iwai1c209302009-07-22 15:17:45 +020014749 dac = alc861_look_for_dac(codec, nid);
14750 if (!dac)
14751 continue;
14752 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010014753 }
Kailang Yangdf694da2005-12-05 19:42:22 +010014754 return 0;
14755}
14756
Takashi Iwai1c209302009-07-22 15:17:45 +020014757static int alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
14758 hda_nid_t nid, unsigned int chs)
Kailang Yangdf694da2005-12-05 19:42:22 +010014759{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020014760 return add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai1c209302009-07-22 15:17:45 +020014761 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
14762}
14763
14764/* add playback controls from the parsed DAC table */
14765static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
14766 const struct auto_pin_cfg *cfg)
14767{
14768 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014769 static const char *chname[4] = {
14770 "Front", "Surround", NULL /*CLFE*/, "Side"
14771 };
Kailang Yangdf694da2005-12-05 19:42:22 +010014772 hda_nid_t nid;
Takashi Iwai1c209302009-07-22 15:17:45 +020014773 int i, err;
14774
14775 if (cfg->line_outs == 1) {
14776 const char *pfx = NULL;
14777 if (!cfg->hp_outs)
14778 pfx = "Master";
14779 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
14780 pfx = "Speaker";
14781 if (pfx) {
14782 nid = spec->multiout.dac_nids[0];
14783 return alc861_create_out_sw(codec, pfx, nid, 3);
14784 }
14785 }
Kailang Yangdf694da2005-12-05 19:42:22 +010014786
14787 for (i = 0; i < cfg->line_outs; i++) {
14788 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014789 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010014790 continue;
Takashi Iwai1c209302009-07-22 15:17:45 +020014791 if (i == 2) {
Kailang Yangdf694da2005-12-05 19:42:22 +010014792 /* Center/LFE */
Takashi Iwai1c209302009-07-22 15:17:45 +020014793 err = alc861_create_out_sw(codec, "Center", nid, 1);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014794 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010014795 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020014796 err = alc861_create_out_sw(codec, "LFE", nid, 2);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014797 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010014798 return err;
14799 } else {
Takashi Iwai1c209302009-07-22 15:17:45 +020014800 err = alc861_create_out_sw(codec, chname[i], nid, 3);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014801 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010014802 return err;
14803 }
14804 }
14805 return 0;
14806}
14807
Takashi Iwai1c209302009-07-22 15:17:45 +020014808static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010014809{
Takashi Iwai1c209302009-07-22 15:17:45 +020014810 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010014811 int err;
14812 hda_nid_t nid;
14813
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014814 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010014815 return 0;
14816
14817 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
Takashi Iwai1c209302009-07-22 15:17:45 +020014818 nid = alc861_look_for_dac(codec, pin);
14819 if (nid) {
14820 err = alc861_create_out_sw(codec, "Headphone", nid, 3);
14821 if (err < 0)
14822 return err;
14823 spec->multiout.hp_nid = nid;
14824 }
Kailang Yangdf694da2005-12-05 19:42:22 +010014825 }
14826 return 0;
14827}
14828
14829/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020014830static int alc861_auto_create_input_ctls(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014831 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010014832{
Takashi Iwai05f5f472009-08-25 13:10:18 +020014833 return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x08, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010014834}
14835
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014836static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
14837 hda_nid_t nid,
Takashi Iwai1c209302009-07-22 15:17:45 +020014838 int pin_type, hda_nid_t dac)
Kailang Yangdf694da2005-12-05 19:42:22 +010014839{
Takashi Iwai1c209302009-07-22 15:17:45 +020014840 hda_nid_t mix, srcs[5];
14841 int i, num;
14842
Jacek Luczak564c5be2008-05-03 18:41:23 +020014843 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
14844 pin_type);
Takashi Iwai1c209302009-07-22 15:17:45 +020014845 snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Jacek Luczak564c5be2008-05-03 18:41:23 +020014846 AMP_OUT_UNMUTE);
Takashi Iwai1c209302009-07-22 15:17:45 +020014847 if (snd_hda_get_connections(codec, nid, &mix, 1) != 1)
14848 return;
14849 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
14850 if (num < 0)
14851 return;
14852 for (i = 0; i < num; i++) {
14853 unsigned int mute;
14854 if (srcs[i] == dac || srcs[i] == 0x15)
14855 mute = AMP_IN_UNMUTE(i);
14856 else
14857 mute = AMP_IN_MUTE(i);
14858 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
14859 mute);
14860 }
Kailang Yangdf694da2005-12-05 19:42:22 +010014861}
14862
14863static void alc861_auto_init_multi_out(struct hda_codec *codec)
14864{
14865 struct alc_spec *spec = codec->spec;
14866 int i;
14867
14868 for (i = 0; i < spec->autocfg.line_outs; i++) {
14869 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020014870 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010014871 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020014872 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014873 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010014874 }
14875}
14876
14877static void alc861_auto_init_hp_out(struct hda_codec *codec)
14878{
14879 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010014880
Takashi Iwai15870f02009-10-05 08:25:13 +020014881 if (spec->autocfg.hp_outs)
14882 alc861_auto_set_output_and_unmute(codec,
14883 spec->autocfg.hp_pins[0],
14884 PIN_HP,
Takashi Iwai1c209302009-07-22 15:17:45 +020014885 spec->multiout.hp_nid);
Takashi Iwai15870f02009-10-05 08:25:13 +020014886 if (spec->autocfg.speaker_outs)
14887 alc861_auto_set_output_and_unmute(codec,
14888 spec->autocfg.speaker_pins[0],
14889 PIN_OUT,
Takashi Iwai1c209302009-07-22 15:17:45 +020014890 spec->multiout.dac_nids[0]);
Kailang Yangdf694da2005-12-05 19:42:22 +010014891}
14892
14893static void alc861_auto_init_analog_input(struct hda_codec *codec)
14894{
14895 struct alc_spec *spec = codec->spec;
14896 int i;
14897
14898 for (i = 0; i < AUTO_PIN_LAST; i++) {
14899 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai23f0c042009-02-26 13:03:58 +010014900 if (nid >= 0x0c && nid <= 0x11)
14901 alc_set_input_pin(codec, nid, i);
Kailang Yangdf694da2005-12-05 19:42:22 +010014902 }
14903}
14904
14905/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014906/* return 1 if successful, 0 if the proper config is not found,
14907 * or a negative error code
14908 */
Kailang Yangdf694da2005-12-05 19:42:22 +010014909static int alc861_parse_auto_config(struct hda_codec *codec)
14910{
14911 struct alc_spec *spec = codec->spec;
14912 int err;
14913 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
14914
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014915 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
14916 alc861_ignore);
14917 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010014918 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014919 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010014920 return 0; /* can't find valid BIOS pin config */
14921
Takashi Iwai1c209302009-07-22 15:17:45 +020014922 err = alc861_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014923 if (err < 0)
14924 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020014925 err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014926 if (err < 0)
14927 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020014928 err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014929 if (err < 0)
14930 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020014931 err = alc861_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014932 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010014933 return err;
14934
14935 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
14936
Takashi Iwai0852d7a2009-02-11 11:35:15 +010014937 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010014938 spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
14939
Takashi Iwai603c4012008-07-30 15:01:44 +020014940 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010014941 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010014942
Takashi Iwaid88897e2008-10-31 15:01:37 +010014943 add_verb(spec, alc861_auto_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +010014944
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020014945 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020014946 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010014947
14948 spec->adc_nids = alc861_adc_nids;
14949 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
Takashi Iwaib59bdf32009-08-11 09:47:30 +020014950 set_capture_mixer(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010014951
Takashi Iwai4a79ba32009-04-22 16:31:35 +020014952 alc_ssid_check(codec, 0x0e, 0x0f, 0x0b);
14953
Kailang Yangdf694da2005-12-05 19:42:22 +010014954 return 1;
14955}
14956
Takashi Iwaiae6b8132006-03-03 16:47:17 +010014957/* additional initialization for auto-configuration model */
14958static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010014959{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014960 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010014961 alc861_auto_init_multi_out(codec);
14962 alc861_auto_init_hp_out(codec);
14963 alc861_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014964 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020014965 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010014966}
14967
Takashi Iwaicb53c622007-08-10 17:21:45 +020014968#ifdef CONFIG_SND_HDA_POWER_SAVE
14969static struct hda_amp_list alc861_loopbacks[] = {
14970 { 0x15, HDA_INPUT, 0 },
14971 { 0x15, HDA_INPUT, 1 },
14972 { 0x15, HDA_INPUT, 2 },
14973 { 0x15, HDA_INPUT, 3 },
14974 { } /* end */
14975};
14976#endif
14977
Kailang Yangdf694da2005-12-05 19:42:22 +010014978
14979/*
14980 * configuration and preset
14981 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010014982static const char *alc861_models[ALC861_MODEL_LAST] = {
14983 [ALC861_3ST] = "3stack",
14984 [ALC660_3ST] = "3stack-660",
14985 [ALC861_3ST_DIG] = "3stack-dig",
14986 [ALC861_6ST_DIG] = "6stack-dig",
14987 [ALC861_UNIWILL_M31] = "uniwill-m31",
14988 [ALC861_TOSHIBA] = "toshiba",
14989 [ALC861_ASUS] = "asus",
14990 [ALC861_ASUS_LAPTOP] = "asus-laptop",
14991 [ALC861_AUTO] = "auto",
14992};
14993
14994static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010014995 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010014996 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
14997 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
14998 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010014999 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020015000 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010015001 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020015002 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
15003 * Any other models that need this preset?
15004 */
15005 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020015006 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
15007 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015008 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
15009 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
15010 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
15011 /* FIXME: the below seems conflict */
15012 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
15013 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
15014 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010015015 {}
15016};
15017
15018static struct alc_config_preset alc861_presets[] = {
15019 [ALC861_3ST] = {
15020 .mixers = { alc861_3ST_mixer },
15021 .init_verbs = { alc861_threestack_init_verbs },
15022 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15023 .dac_nids = alc861_dac_nids,
15024 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
15025 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020015026 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010015027 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15028 .adc_nids = alc861_adc_nids,
15029 .input_mux = &alc861_capture_source,
15030 },
15031 [ALC861_3ST_DIG] = {
15032 .mixers = { alc861_base_mixer },
15033 .init_verbs = { alc861_threestack_init_verbs },
15034 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15035 .dac_nids = alc861_dac_nids,
15036 .dig_out_nid = ALC861_DIGOUT_NID,
15037 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
15038 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020015039 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010015040 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15041 .adc_nids = alc861_adc_nids,
15042 .input_mux = &alc861_capture_source,
15043 },
15044 [ALC861_6ST_DIG] = {
15045 .mixers = { alc861_base_mixer },
15046 .init_verbs = { alc861_base_init_verbs },
15047 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15048 .dac_nids = alc861_dac_nids,
15049 .dig_out_nid = ALC861_DIGOUT_NID,
15050 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
15051 .channel_mode = alc861_8ch_modes,
15052 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15053 .adc_nids = alc861_adc_nids,
15054 .input_mux = &alc861_capture_source,
15055 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015056 [ALC660_3ST] = {
15057 .mixers = { alc861_3ST_mixer },
15058 .init_verbs = { alc861_threestack_init_verbs },
15059 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
15060 .dac_nids = alc660_dac_nids,
15061 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
15062 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020015063 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015064 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15065 .adc_nids = alc861_adc_nids,
15066 .input_mux = &alc861_capture_source,
15067 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015068 [ALC861_UNIWILL_M31] = {
15069 .mixers = { alc861_uniwill_m31_mixer },
15070 .init_verbs = { alc861_uniwill_m31_init_verbs },
15071 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15072 .dac_nids = alc861_dac_nids,
15073 .dig_out_nid = ALC861_DIGOUT_NID,
15074 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
15075 .channel_mode = alc861_uniwill_m31_modes,
15076 .need_dac_fix = 1,
15077 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15078 .adc_nids = alc861_adc_nids,
15079 .input_mux = &alc861_capture_source,
15080 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015081 [ALC861_TOSHIBA] = {
15082 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015083 .init_verbs = { alc861_base_init_verbs,
15084 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015085 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15086 .dac_nids = alc861_dac_nids,
15087 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
15088 .channel_mode = alc883_3ST_2ch_modes,
15089 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15090 .adc_nids = alc861_adc_nids,
15091 .input_mux = &alc861_capture_source,
15092 .unsol_event = alc861_toshiba_unsol_event,
15093 .init_hook = alc861_toshiba_automute,
15094 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015095 [ALC861_ASUS] = {
15096 .mixers = { alc861_asus_mixer },
15097 .init_verbs = { alc861_asus_init_verbs },
15098 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15099 .dac_nids = alc861_dac_nids,
15100 .dig_out_nid = ALC861_DIGOUT_NID,
15101 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
15102 .channel_mode = alc861_asus_modes,
15103 .need_dac_fix = 1,
15104 .hp_nid = 0x06,
15105 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15106 .adc_nids = alc861_adc_nids,
15107 .input_mux = &alc861_capture_source,
15108 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015109 [ALC861_ASUS_LAPTOP] = {
15110 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
15111 .init_verbs = { alc861_asus_init_verbs,
15112 alc861_asus_laptop_init_verbs },
15113 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15114 .dac_nids = alc861_dac_nids,
15115 .dig_out_nid = ALC861_DIGOUT_NID,
15116 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
15117 .channel_mode = alc883_3ST_2ch_modes,
15118 .need_dac_fix = 1,
15119 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15120 .adc_nids = alc861_adc_nids,
15121 .input_mux = &alc861_capture_source,
15122 },
15123};
Kailang Yangdf694da2005-12-05 19:42:22 +010015124
Takashi Iwaicfc9b062009-12-01 12:19:37 +010015125/* Pin config fixes */
15126enum {
15127 PINFIX_FSC_AMILO_PI1505,
15128};
15129
15130static struct alc_pincfg alc861_fsc_amilo_pi1505_pinfix[] = {
15131 { 0x0b, 0x0221101f }, /* HP */
15132 { 0x0f, 0x90170310 }, /* speaker */
15133 { }
15134};
15135
15136static const struct alc_fixup alc861_fixups[] = {
15137 [PINFIX_FSC_AMILO_PI1505] = {
15138 .pins = alc861_fsc_amilo_pi1505_pinfix
15139 },
15140};
15141
15142static struct snd_pci_quirk alc861_fixup_tbl[] = {
15143 SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
15144 {}
15145};
Kailang Yangdf694da2005-12-05 19:42:22 +010015146
15147static int patch_alc861(struct hda_codec *codec)
15148{
15149 struct alc_spec *spec;
15150 int board_config;
15151 int err;
15152
Robert P. J. Daydc041e02006-12-19 14:44:15 +010015153 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010015154 if (spec == NULL)
15155 return -ENOMEM;
15156
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015157 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015158
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015159 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
15160 alc861_models,
15161 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015162
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015163 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020015164 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
15165 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010015166 board_config = ALC861_AUTO;
15167 }
15168
Takashi Iwaicfc9b062009-12-01 12:19:37 +010015169 alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups);
15170
Kailang Yangdf694da2005-12-05 19:42:22 +010015171 if (board_config == ALC861_AUTO) {
15172 /* automatic parse from the BIOS config */
15173 err = alc861_parse_auto_config(codec);
15174 if (err < 0) {
15175 alc_free(codec);
15176 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015177 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015178 printk(KERN_INFO
15179 "hda_codec: Cannot set up configuration "
15180 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010015181 board_config = ALC861_3ST_DIG;
15182 }
15183 }
15184
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090015185 err = snd_hda_attach_beep_device(codec, 0x23);
15186 if (err < 0) {
15187 alc_free(codec);
15188 return err;
15189 }
15190
Kailang Yangdf694da2005-12-05 19:42:22 +010015191 if (board_config != ALC861_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020015192 setup_preset(codec, &alc861_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010015193
Kailang Yangdf694da2005-12-05 19:42:22 +010015194 spec->stream_analog_playback = &alc861_pcm_analog_playback;
15195 spec->stream_analog_capture = &alc861_pcm_analog_capture;
15196
Kailang Yangdf694da2005-12-05 19:42:22 +010015197 spec->stream_digital_playback = &alc861_pcm_digital_playback;
15198 spec->stream_digital_capture = &alc861_pcm_digital_capture;
15199
Takashi Iwaic7a8eb12010-01-14 12:39:02 +010015200 if (!spec->cap_mixer)
15201 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010015202 set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
15203
Takashi Iwai2134ea42008-01-10 16:53:55 +010015204 spec->vmaster_nid = 0x03;
15205
Kailang Yangdf694da2005-12-05 19:42:22 +010015206 codec->patch_ops = alc_patch_ops;
Daniel T Chenc97259d2009-12-27 18:52:08 -050015207 if (board_config == ALC861_AUTO) {
Takashi Iwaiae6b8132006-03-03 16:47:17 +010015208 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020015209#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050015210 spec->power_hook = alc_power_eapd;
15211#endif
15212 }
15213#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaicb53c622007-08-10 17:21:45 +020015214 if (!spec->loopback.amplist)
15215 spec->loopback.amplist = alc861_loopbacks;
15216#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020015217
Kailang Yangdf694da2005-12-05 19:42:22 +010015218 return 0;
15219}
15220
15221/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015222 * ALC861-VD support
15223 *
15224 * Based on ALC882
15225 *
15226 * In addition, an independent DAC
15227 */
15228#define ALC861VD_DIGOUT_NID 0x06
15229
15230static hda_nid_t alc861vd_dac_nids[4] = {
15231 /* front, surr, clfe, side surr */
15232 0x02, 0x03, 0x04, 0x05
15233};
15234
15235/* dac_nids for ALC660vd are in a different order - according to
15236 * Realtek's driver.
Sasha Alexandrdef319f2009-06-16 16:00:15 -040015237 * This should probably result in a different mixer for 6stack models
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015238 * of ALC660vd codecs, but for now there is only 3stack mixer
15239 * - and it is the same as in 861vd.
15240 * adc_nids in ALC660vd are (is) the same as in 861vd
15241 */
15242static hda_nid_t alc660vd_dac_nids[3] = {
15243 /* front, rear, clfe, rear_surr */
15244 0x02, 0x04, 0x03
15245};
15246
15247static hda_nid_t alc861vd_adc_nids[1] = {
15248 /* ADC0 */
15249 0x09,
15250};
15251
Takashi Iwaie1406342008-02-11 18:32:32 +010015252static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
15253
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015254/* input MUX */
15255/* FIXME: should be a matrix-type input source selection */
15256static struct hda_input_mux alc861vd_capture_source = {
15257 .num_items = 4,
15258 .items = {
15259 { "Mic", 0x0 },
15260 { "Front Mic", 0x1 },
15261 { "Line", 0x2 },
15262 { "CD", 0x4 },
15263 },
15264};
15265
Kailang Yang272a5272007-05-14 11:00:38 +020015266static struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010015267 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020015268 .items = {
Tobin Davisb419f342008-03-07 11:57:51 +010015269 { "Ext Mic", 0x0 },
15270 { "Int Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020015271 },
15272};
15273
Kailang Yangd1a991a2007-08-15 16:21:59 +020015274static struct hda_input_mux alc861vd_hp_capture_source = {
15275 .num_items = 2,
15276 .items = {
15277 { "Front Mic", 0x0 },
15278 { "ATAPI Mic", 0x1 },
15279 },
15280};
15281
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015282/*
15283 * 2ch mode
15284 */
15285static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
15286 { 2, NULL }
15287};
15288
15289/*
15290 * 6ch mode
15291 */
15292static struct hda_verb alc861vd_6stack_ch6_init[] = {
15293 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15294 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15295 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15296 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15297 { } /* end */
15298};
15299
15300/*
15301 * 8ch mode
15302 */
15303static struct hda_verb alc861vd_6stack_ch8_init[] = {
15304 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15305 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15306 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15307 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15308 { } /* end */
15309};
15310
15311static struct hda_channel_mode alc861vd_6stack_modes[2] = {
15312 { 6, alc861vd_6stack_ch6_init },
15313 { 8, alc861vd_6stack_ch8_init },
15314};
15315
15316static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
15317 {
15318 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15319 .name = "Channel Mode",
15320 .info = alc_ch_mode_info,
15321 .get = alc_ch_mode_get,
15322 .put = alc_ch_mode_put,
15323 },
15324 { } /* end */
15325};
15326
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015327/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
15328 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
15329 */
15330static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
15331 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15332 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
15333
15334 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15335 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
15336
15337 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
15338 HDA_OUTPUT),
15339 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
15340 HDA_OUTPUT),
15341 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
15342 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
15343
15344 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
15345 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
15346
15347 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15348
15349 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
15350 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15351 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15352
15353 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
15354 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15355 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15356
15357 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15358 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15359
15360 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
15361 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
15362
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015363 { } /* end */
15364};
15365
15366static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
15367 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15368 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
15369
15370 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15371
15372 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
15373 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15374 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15375
15376 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
15377 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15378 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15379
15380 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15381 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15382
15383 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
15384 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
15385
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015386 { } /* end */
15387};
15388
Kailang Yangbdd148a2007-05-08 15:19:08 +020015389static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
15390 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15391 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
15392 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
15393
15394 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15395
15396 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
15397 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15398 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15399
15400 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
15401 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15402 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15403
15404 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
15405 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
15406
15407 { } /* end */
15408};
15409
Tobin Davisb419f342008-03-07 11:57:51 +010015410/* Pin assignment: Speaker=0x14, HP = 0x15,
15411 * Ext Mic=0x18, Int Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020015412 */
15413static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010015414 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15415 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020015416 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15417 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisb419f342008-03-07 11:57:51 +010015418 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
15419 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15420 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15421 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
15422 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15423 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020015424 { } /* end */
15425};
15426
Kailang Yangd1a991a2007-08-15 16:21:59 +020015427/* Pin assignment: Speaker=0x14, Line-out = 0x15,
15428 * Front Mic=0x18, ATAPI Mic = 0x19,
15429 */
15430static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
15431 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15432 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
15433 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15434 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
15435 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15436 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15437 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15438 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020015439
Kailang Yangd1a991a2007-08-15 16:21:59 +020015440 { } /* end */
15441};
15442
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015443/*
15444 * generic initialization of ADC, input mixers and output mixers
15445 */
15446static struct hda_verb alc861vd_volume_init_verbs[] = {
15447 /*
15448 * Unmute ADC0 and set the default input to mic-in
15449 */
15450 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
15451 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15452
15453 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
15454 * the analog-loopback mixer widget
15455 */
15456 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020015457 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15458 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15459 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15460 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
15461 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015462
15463 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020015464 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15465 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15466 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015467 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015468
15469 /*
15470 * Set up output mixers (0x02 - 0x05)
15471 */
15472 /* set vol=0 to output mixers */
15473 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15474 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15475 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15476 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15477
15478 /* set up input amps for analog loopback */
15479 /* Amp Indices: DAC = 0, mixer = 1 */
15480 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15481 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15482 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15483 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15484 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15485 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15486 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15487 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15488
15489 { }
15490};
15491
15492/*
15493 * 3-stack pin configuration:
15494 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
15495 */
15496static struct hda_verb alc861vd_3stack_init_verbs[] = {
15497 /*
15498 * Set pin mode and muting
15499 */
15500 /* set front pin widgets 0x14 for output */
15501 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15502 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15503 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
15504
15505 /* Mic (rear) pin: input vref at 80% */
15506 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
15507 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15508 /* Front Mic pin: input vref at 80% */
15509 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
15510 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15511 /* Line In pin: input */
15512 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15513 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15514 /* Line-2 In: Headphone output (output 0 - 0x0c) */
15515 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15516 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15517 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
15518 /* CD pin widget for input */
15519 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15520
15521 { }
15522};
15523
15524/*
15525 * 6-stack pin configuration:
15526 */
15527static struct hda_verb alc861vd_6stack_init_verbs[] = {
15528 /*
15529 * Set pin mode and muting
15530 */
15531 /* set front pin widgets 0x14 for output */
15532 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15533 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15534 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
15535
15536 /* Rear Pin: output 1 (0x0d) */
15537 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15538 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15539 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
15540 /* CLFE Pin: output 2 (0x0e) */
15541 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15542 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15543 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
15544 /* Side Pin: output 3 (0x0f) */
15545 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15546 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15547 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
15548
15549 /* Mic (rear) pin: input vref at 80% */
15550 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
15551 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15552 /* Front Mic pin: input vref at 80% */
15553 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
15554 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15555 /* Line In pin: input */
15556 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15557 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15558 /* Line-2 In: Headphone output (output 0 - 0x0c) */
15559 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15560 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15561 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
15562 /* CD pin widget for input */
15563 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15564
15565 { }
15566};
15567
Kailang Yangbdd148a2007-05-08 15:19:08 +020015568static struct hda_verb alc861vd_eapd_verbs[] = {
15569 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
15570 { }
15571};
15572
Kailang Yangf9423e72008-05-27 12:32:25 +020015573static struct hda_verb alc660vd_eapd_verbs[] = {
15574 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
15575 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
15576 { }
15577};
15578
Kailang Yangbdd148a2007-05-08 15:19:08 +020015579static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
15580 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15581 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15582 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
15583 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020015584 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020015585 {}
15586};
15587
Kailang Yangbdd148a2007-05-08 15:19:08 +020015588static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
15589{
15590 unsigned int present;
15591 unsigned char bits;
15592
Wu Fengguang864f92b2009-11-18 12:38:02 +080015593 present = snd_hda_jack_detect(codec, 0x18);
Takashi Iwai47fd8302007-08-10 17:11:07 +020015594 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080015595
Takashi Iwai47fd8302007-08-10 17:11:07 +020015596 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
15597 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020015598}
15599
Takashi Iwai4f5d17062009-08-11 18:17:46 +020015600static void alc861vd_lenovo_setup(struct hda_codec *codec)
Kailang Yangbdd148a2007-05-08 15:19:08 +020015601{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015602 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015603 spec->autocfg.hp_pins[0] = 0x1b;
15604 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020015605}
15606
15607static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
15608{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015609 alc_automute_amp(codec);
Kailang Yangbdd148a2007-05-08 15:19:08 +020015610 alc861vd_lenovo_mic_automute(codec);
15611}
15612
15613static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
15614 unsigned int res)
15615{
15616 switch (res >> 26) {
Kailang Yangbdd148a2007-05-08 15:19:08 +020015617 case ALC880_MIC_EVENT:
15618 alc861vd_lenovo_mic_automute(codec);
15619 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015620 default:
15621 alc_automute_amp_unsol_event(codec, res);
15622 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +020015623 }
15624}
15625
Kailang Yang272a5272007-05-14 11:00:38 +020015626static struct hda_verb alc861vd_dallas_verbs[] = {
15627 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15628 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15629 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15630 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15631
15632 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15633 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15634 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15635 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15636 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15637 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15638 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15639 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015640
Kailang Yang272a5272007-05-14 11:00:38 +020015641 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15642 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15643 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15644 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15645 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15646 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15647 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15648 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15649
15650 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
15651 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15652 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
15653 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15654 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15655 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15656 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15657 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15658
15659 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15660 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
15661 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15662 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
15663
15664 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015665 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020015666 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15667
15668 { } /* end */
15669};
15670
15671/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020015672static void alc861vd_dallas_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +020015673{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015674 struct alc_spec *spec = codec->spec;
Kailang Yang272a5272007-05-14 11:00:38 +020015675
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015676 spec->autocfg.hp_pins[0] = 0x15;
15677 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang272a5272007-05-14 11:00:38 +020015678}
15679
Takashi Iwaicb53c622007-08-10 17:21:45 +020015680#ifdef CONFIG_SND_HDA_POWER_SAVE
15681#define alc861vd_loopbacks alc880_loopbacks
15682#endif
15683
Sasha Alexandrdef319f2009-06-16 16:00:15 -040015684/* pcm configuration: identical with ALC880 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015685#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
15686#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
15687#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
15688#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
15689
15690/*
15691 * configuration and preset
15692 */
15693static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
15694 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020015695 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Takashi Iwai13c94742008-11-05 08:06:08 +010015696 [ALC660VD_ASUS_V1S] = "asus-v1s",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015697 [ALC861VD_3ST] = "3stack",
15698 [ALC861VD_3ST_DIG] = "3stack-digout",
15699 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020015700 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020015701 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020015702 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015703 [ALC861VD_AUTO] = "auto",
15704};
15705
15706static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015707 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
15708 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010015709 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020015710 /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */
Takashi Iwai13c94742008-11-05 08:06:08 +010015711 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
Mike Crash6963f842007-06-25 12:12:51 +020015712 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015713 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015714 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020015715 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Takashi Iwaice577e82009-08-03 08:23:52 +020015716 SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai542d7c62007-08-16 18:57:30 +020015717 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010015718 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020015719 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010015720 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020015721 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015722 {}
15723};
15724
15725static struct alc_config_preset alc861vd_presets[] = {
15726 [ALC660VD_3ST] = {
15727 .mixers = { alc861vd_3st_mixer },
15728 .init_verbs = { alc861vd_volume_init_verbs,
15729 alc861vd_3stack_init_verbs },
15730 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
15731 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015732 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
15733 .channel_mode = alc861vd_3stack_2ch_modes,
15734 .input_mux = &alc861vd_capture_source,
15735 },
Mike Crash6963f842007-06-25 12:12:51 +020015736 [ALC660VD_3ST_DIG] = {
15737 .mixers = { alc861vd_3st_mixer },
15738 .init_verbs = { alc861vd_volume_init_verbs,
15739 alc861vd_3stack_init_verbs },
15740 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
15741 .dac_nids = alc660vd_dac_nids,
15742 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020015743 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
15744 .channel_mode = alc861vd_3stack_2ch_modes,
15745 .input_mux = &alc861vd_capture_source,
15746 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015747 [ALC861VD_3ST] = {
15748 .mixers = { alc861vd_3st_mixer },
15749 .init_verbs = { alc861vd_volume_init_verbs,
15750 alc861vd_3stack_init_verbs },
15751 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
15752 .dac_nids = alc861vd_dac_nids,
15753 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
15754 .channel_mode = alc861vd_3stack_2ch_modes,
15755 .input_mux = &alc861vd_capture_source,
15756 },
15757 [ALC861VD_3ST_DIG] = {
15758 .mixers = { alc861vd_3st_mixer },
15759 .init_verbs = { alc861vd_volume_init_verbs,
15760 alc861vd_3stack_init_verbs },
15761 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
15762 .dac_nids = alc861vd_dac_nids,
15763 .dig_out_nid = ALC861VD_DIGOUT_NID,
15764 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
15765 .channel_mode = alc861vd_3stack_2ch_modes,
15766 .input_mux = &alc861vd_capture_source,
15767 },
15768 [ALC861VD_6ST_DIG] = {
15769 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
15770 .init_verbs = { alc861vd_volume_init_verbs,
15771 alc861vd_6stack_init_verbs },
15772 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
15773 .dac_nids = alc861vd_dac_nids,
15774 .dig_out_nid = ALC861VD_DIGOUT_NID,
15775 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
15776 .channel_mode = alc861vd_6stack_modes,
15777 .input_mux = &alc861vd_capture_source,
15778 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020015779 [ALC861VD_LENOVO] = {
15780 .mixers = { alc861vd_lenovo_mixer },
15781 .init_verbs = { alc861vd_volume_init_verbs,
15782 alc861vd_3stack_init_verbs,
15783 alc861vd_eapd_verbs,
15784 alc861vd_lenovo_unsol_verbs },
15785 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
15786 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020015787 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
15788 .channel_mode = alc861vd_3stack_2ch_modes,
15789 .input_mux = &alc861vd_capture_source,
15790 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020015791 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015792 .init_hook = alc861vd_lenovo_init_hook,
Kailang Yangbdd148a2007-05-08 15:19:08 +020015793 },
Kailang Yang272a5272007-05-14 11:00:38 +020015794 [ALC861VD_DALLAS] = {
15795 .mixers = { alc861vd_dallas_mixer },
15796 .init_verbs = { alc861vd_dallas_verbs },
15797 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
15798 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020015799 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
15800 .channel_mode = alc861vd_3stack_2ch_modes,
15801 .input_mux = &alc861vd_dallas_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015802 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020015803 .setup = alc861vd_dallas_setup,
15804 .init_hook = alc_automute_amp,
Kailang Yangd1a991a2007-08-15 16:21:59 +020015805 },
15806 [ALC861VD_HP] = {
15807 .mixers = { alc861vd_hp_mixer },
15808 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
15809 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
15810 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020015811 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020015812 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
15813 .channel_mode = alc861vd_3stack_2ch_modes,
15814 .input_mux = &alc861vd_hp_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015815 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020015816 .setup = alc861vd_dallas_setup,
15817 .init_hook = alc_automute_amp,
Kailang Yangea1fb292008-08-26 12:58:38 +020015818 },
Takashi Iwai13c94742008-11-05 08:06:08 +010015819 [ALC660VD_ASUS_V1S] = {
15820 .mixers = { alc861vd_lenovo_mixer },
15821 .init_verbs = { alc861vd_volume_init_verbs,
15822 alc861vd_3stack_init_verbs,
15823 alc861vd_eapd_verbs,
15824 alc861vd_lenovo_unsol_verbs },
15825 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
15826 .dac_nids = alc660vd_dac_nids,
15827 .dig_out_nid = ALC861VD_DIGOUT_NID,
15828 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
15829 .channel_mode = alc861vd_3stack_2ch_modes,
15830 .input_mux = &alc861vd_capture_source,
15831 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020015832 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015833 .init_hook = alc861vd_lenovo_init_hook,
Takashi Iwai13c94742008-11-05 08:06:08 +010015834 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015835};
15836
15837/*
15838 * BIOS auto configuration
15839 */
Takashi Iwai05f5f472009-08-25 13:10:18 +020015840static int alc861vd_auto_create_input_ctls(struct hda_codec *codec,
15841 const struct auto_pin_cfg *cfg)
15842{
Takashi Iwai9c0afc82010-01-12 14:00:11 +010015843 return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x22, 0);
Takashi Iwai05f5f472009-08-25 13:10:18 +020015844}
15845
15846
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015847static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
15848 hda_nid_t nid, int pin_type, int dac_idx)
15849{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015850 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015851}
15852
15853static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
15854{
15855 struct alc_spec *spec = codec->spec;
15856 int i;
15857
15858 for (i = 0; i <= HDA_SIDE; i++) {
15859 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015860 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015861 if (nid)
15862 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015863 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015864 }
15865}
15866
15867
15868static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
15869{
15870 struct alc_spec *spec = codec->spec;
15871 hda_nid_t pin;
15872
15873 pin = spec->autocfg.hp_pins[0];
Sasha Alexandrdef319f2009-06-16 16:00:15 -040015874 if (pin) /* connect to front and use dac 0 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015875 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015876 pin = spec->autocfg.speaker_pins[0];
15877 if (pin)
15878 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015879}
15880
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015881#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
15882
15883static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
15884{
15885 struct alc_spec *spec = codec->spec;
15886 int i;
15887
15888 for (i = 0; i < AUTO_PIN_LAST; i++) {
15889 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai05f5f472009-08-25 13:10:18 +020015890 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +010015891 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +010015892 if (nid != ALC861VD_PIN_CD_NID &&
15893 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015894 snd_hda_codec_write(codec, nid, 0,
15895 AC_VERB_SET_AMP_GAIN_MUTE,
15896 AMP_OUT_MUTE);
15897 }
15898 }
15899}
15900
Takashi Iwaif511b012008-08-15 16:46:42 +020015901#define alc861vd_auto_init_input_src alc882_auto_init_input_src
15902
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015903#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
15904#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
15905
15906/* add playback controls from the parsed DAC table */
15907/* Based on ALC880 version. But ALC861VD has separate,
15908 * different NIDs for mute/unmute switch and volume control */
15909static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
15910 const struct auto_pin_cfg *cfg)
15911{
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015912 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
15913 hda_nid_t nid_v, nid_s;
15914 int i, err;
15915
15916 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015917 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015918 continue;
15919 nid_v = alc861vd_idx_to_mixer_vol(
15920 alc880_dac_to_idx(
15921 spec->multiout.dac_nids[i]));
15922 nid_s = alc861vd_idx_to_mixer_switch(
15923 alc880_dac_to_idx(
15924 spec->multiout.dac_nids[i]));
15925
15926 if (i == 2) {
15927 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015928 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
15929 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015930 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
15931 HDA_OUTPUT));
15932 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015933 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015934 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
15935 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015936 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
15937 HDA_OUTPUT));
15938 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015939 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015940 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
15941 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015942 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
15943 HDA_INPUT));
15944 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015945 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015946 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
15947 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015948 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
15949 HDA_INPUT));
15950 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015951 return err;
15952 } else {
Takashi Iwaia4fcd492009-08-25 16:12:15 +020015953 const char *pfx;
15954 if (cfg->line_outs == 1 &&
15955 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
15956 if (!cfg->hp_pins)
15957 pfx = "Speaker";
15958 else
15959 pfx = "PCM";
15960 } else
15961 pfx = chname[i];
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015962 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015963 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
15964 HDA_OUTPUT));
15965 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015966 return err;
Takashi Iwaia4fcd492009-08-25 16:12:15 +020015967 if (cfg->line_outs == 1 &&
15968 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
15969 pfx = "Speaker";
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015970 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Kailang Yangbdd148a2007-05-08 15:19:08 +020015971 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015972 HDA_INPUT));
15973 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015974 return err;
15975 }
15976 }
15977 return 0;
15978}
15979
15980/* add playback controls for speaker and HP outputs */
15981/* Based on ALC880 version. But ALC861VD has separate,
15982 * different NIDs for mute/unmute switch and volume control */
15983static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
15984 hda_nid_t pin, const char *pfx)
15985{
15986 hda_nid_t nid_v, nid_s;
15987 int err;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015988
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015989 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015990 return 0;
15991
15992 if (alc880_is_fixed_pin(pin)) {
15993 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
15994 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015995 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015996 spec->multiout.hp_nid = nid_v;
15997 else
15998 spec->multiout.extra_out_nid[0] = nid_v;
15999 /* control HP volume/switch on the output mixer amp */
16000 nid_v = alc861vd_idx_to_mixer_vol(
16001 alc880_fixed_pin_idx(pin));
16002 nid_s = alc861vd_idx_to_mixer_switch(
16003 alc880_fixed_pin_idx(pin));
16004
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016005 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016006 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
16007 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016008 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016009 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016010 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
16011 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016012 return err;
16013 } else if (alc880_is_multi_pin(pin)) {
16014 /* set manual connection */
16015 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016016 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016017 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
16018 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016019 return err;
16020 }
16021 return 0;
16022}
16023
16024/* parse the BIOS configuration and set up the alc_spec
16025 * return 1 if successful, 0 if the proper config is not found,
16026 * or a negative error code
16027 * Based on ALC880 version - had to change it to override
16028 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
16029static int alc861vd_parse_auto_config(struct hda_codec *codec)
16030{
16031 struct alc_spec *spec = codec->spec;
16032 int err;
16033 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
16034
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016035 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
16036 alc861vd_ignore);
16037 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016038 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016039 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016040 return 0; /* can't find valid BIOS pin config */
16041
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016042 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
16043 if (err < 0)
16044 return err;
16045 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
16046 if (err < 0)
16047 return err;
16048 err = alc861vd_auto_create_extra_out(spec,
16049 spec->autocfg.speaker_pins[0],
16050 "Speaker");
16051 if (err < 0)
16052 return err;
16053 err = alc861vd_auto_create_extra_out(spec,
16054 spec->autocfg.hp_pins[0],
16055 "Headphone");
16056 if (err < 0)
16057 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020016058 err = alc861vd_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016059 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016060 return err;
16061
16062 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
16063
Takashi Iwai0852d7a2009-02-11 11:35:15 +010016064 if (spec->autocfg.dig_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016065 spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
16066
Takashi Iwai603c4012008-07-30 15:01:44 +020016067 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010016068 add_mixer(spec, spec->kctls.list);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016069
Takashi Iwaid88897e2008-10-31 15:01:37 +010016070 add_verb(spec, alc861vd_volume_init_verbs);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016071
16072 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020016073 spec->input_mux = &spec->private_imux[0];
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016074
Takashi Iwai776e1842007-08-29 15:07:11 +020016075 err = alc_auto_add_mic_boost(codec);
16076 if (err < 0)
16077 return err;
16078
Takashi Iwai4a79ba32009-04-22 16:31:35 +020016079 alc_ssid_check(codec, 0x15, 0x1b, 0x14);
16080
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016081 return 1;
16082}
16083
16084/* additional initialization for auto-configuration model */
16085static void alc861vd_auto_init(struct hda_codec *codec)
16086{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016087 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016088 alc861vd_auto_init_multi_out(codec);
16089 alc861vd_auto_init_hp_out(codec);
16090 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020016091 alc861vd_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016092 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020016093 alc_inithook(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016094}
16095
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016096enum {
16097 ALC660VD_FIX_ASUS_GPIO1
16098};
16099
16100/* reset GPIO1 */
16101static const struct hda_verb alc660vd_fix_asus_gpio1_verbs[] = {
16102 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
16103 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
16104 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
16105 { }
16106};
16107
16108static const struct alc_fixup alc861vd_fixups[] = {
16109 [ALC660VD_FIX_ASUS_GPIO1] = {
16110 .verbs = alc660vd_fix_asus_gpio1_verbs,
16111 },
16112};
16113
16114static struct snd_pci_quirk alc861vd_fixup_tbl[] = {
16115 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
16116 {}
16117};
16118
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016119static int patch_alc861vd(struct hda_codec *codec)
16120{
16121 struct alc_spec *spec;
16122 int err, board_config;
16123
16124 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
16125 if (spec == NULL)
16126 return -ENOMEM;
16127
16128 codec->spec = spec;
16129
16130 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
16131 alc861vd_models,
16132 alc861vd_cfg_tbl);
16133
16134 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020016135 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
16136 codec->chip_name);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016137 board_config = ALC861VD_AUTO;
16138 }
16139
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016140 alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups);
16141
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016142 if (board_config == ALC861VD_AUTO) {
16143 /* automatic parse from the BIOS config */
16144 err = alc861vd_parse_auto_config(codec);
16145 if (err < 0) {
16146 alc_free(codec);
16147 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016148 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016149 printk(KERN_INFO
16150 "hda_codec: Cannot set up configuration "
16151 "from BIOS. Using base mode...\n");
16152 board_config = ALC861VD_3ST;
16153 }
16154 }
16155
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090016156 err = snd_hda_attach_beep_device(codec, 0x23);
16157 if (err < 0) {
16158 alc_free(codec);
16159 return err;
16160 }
16161
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016162 if (board_config != ALC861VD_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020016163 setup_preset(codec, &alc861vd_presets[board_config]);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016164
Kailang Yang2f893282008-05-27 12:14:47 +020016165 if (codec->vendor_id == 0x10ec0660) {
Kailang Yangf9423e72008-05-27 12:32:25 +020016166 /* always turn on EAPD */
Takashi Iwaid88897e2008-10-31 15:01:37 +010016167 add_verb(spec, alc660vd_eapd_verbs);
Kailang Yang2f893282008-05-27 12:14:47 +020016168 }
16169
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016170 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
16171 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
16172
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016173 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
16174 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
16175
Takashi Iwaidd704692009-08-11 08:45:11 +020016176 if (!spec->adc_nids) {
16177 spec->adc_nids = alc861vd_adc_nids;
16178 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
16179 }
16180 if (!spec->capsrc_nids)
16181 spec->capsrc_nids = alc861vd_capsrc_nids;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016182
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016183 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010016184 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016185
Takashi Iwai2134ea42008-01-10 16:53:55 +010016186 spec->vmaster_nid = 0x02;
16187
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016188 codec->patch_ops = alc_patch_ops;
16189
16190 if (board_config == ALC861VD_AUTO)
16191 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020016192#ifdef CONFIG_SND_HDA_POWER_SAVE
16193 if (!spec->loopback.amplist)
16194 spec->loopback.amplist = alc861vd_loopbacks;
16195#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016196
16197 return 0;
16198}
16199
16200/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016201 * ALC662 support
16202 *
16203 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
16204 * configuration. Each pin widget can choose any input DACs and a mixer.
16205 * Each ADC is connected from a mixer of all inputs. This makes possible
16206 * 6-channel independent captures.
16207 *
16208 * In addition, an independent DAC for the multi-playback (not used in this
16209 * driver yet).
16210 */
16211#define ALC662_DIGOUT_NID 0x06
16212#define ALC662_DIGIN_NID 0x0a
16213
16214static hda_nid_t alc662_dac_nids[4] = {
16215 /* front, rear, clfe, rear_surr */
16216 0x02, 0x03, 0x04
16217};
16218
Kailang Yang622e84c2009-04-21 07:39:04 +020016219static hda_nid_t alc272_dac_nids[2] = {
16220 0x02, 0x03
16221};
16222
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016223static hda_nid_t alc662_adc_nids[2] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016224 /* ADC1-2 */
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016225 0x09, 0x08
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016226};
Takashi Iwaie1406342008-02-11 18:32:32 +010016227
Kailang Yang622e84c2009-04-21 07:39:04 +020016228static hda_nid_t alc272_adc_nids[1] = {
16229 /* ADC1-2 */
16230 0x08,
16231};
16232
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016233static hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 };
Kailang Yang622e84c2009-04-21 07:39:04 +020016234static hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
16235
Takashi Iwaie1406342008-02-11 18:32:32 +010016236
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016237/* input MUX */
16238/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016239static struct hda_input_mux alc662_capture_source = {
16240 .num_items = 4,
16241 .items = {
16242 { "Mic", 0x0 },
16243 { "Front Mic", 0x1 },
16244 { "Line", 0x2 },
16245 { "CD", 0x4 },
16246 },
16247};
16248
16249static struct hda_input_mux alc662_lenovo_101e_capture_source = {
16250 .num_items = 2,
16251 .items = {
16252 { "Mic", 0x1 },
16253 { "Line", 0x2 },
16254 },
16255};
Kailang Yang291702f2007-10-16 14:28:03 +020016256
Kailang Yang6dda9f42008-05-27 12:05:31 +020016257static struct hda_input_mux alc663_capture_source = {
16258 .num_items = 3,
16259 .items = {
16260 { "Mic", 0x0 },
16261 { "Front Mic", 0x1 },
16262 { "Line", 0x2 },
16263 },
16264};
16265
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016266#if 0 /* set to 1 for testing other input sources below */
Chris Pockelé9541ba12009-05-12 08:08:53 +020016267static struct hda_input_mux alc272_nc10_capture_source = {
16268 .num_items = 16,
16269 .items = {
16270 { "Autoselect Mic", 0x0 },
16271 { "Internal Mic", 0x1 },
16272 { "In-0x02", 0x2 },
16273 { "In-0x03", 0x3 },
16274 { "In-0x04", 0x4 },
16275 { "In-0x05", 0x5 },
16276 { "In-0x06", 0x6 },
16277 { "In-0x07", 0x7 },
16278 { "In-0x08", 0x8 },
16279 { "In-0x09", 0x9 },
16280 { "In-0x0a", 0x0a },
16281 { "In-0x0b", 0x0b },
16282 { "In-0x0c", 0x0c },
16283 { "In-0x0d", 0x0d },
16284 { "In-0x0e", 0x0e },
16285 { "In-0x0f", 0x0f },
16286 },
16287};
16288#endif
16289
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016290/*
16291 * 2ch mode
16292 */
16293static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
16294 { 2, NULL }
16295};
16296
16297/*
16298 * 2ch mode
16299 */
16300static struct hda_verb alc662_3ST_ch2_init[] = {
16301 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
16302 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
16303 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
16304 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
16305 { } /* end */
16306};
16307
16308/*
16309 * 6ch mode
16310 */
16311static struct hda_verb alc662_3ST_ch6_init[] = {
16312 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16313 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
16314 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
16315 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16316 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
16317 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
16318 { } /* end */
16319};
16320
16321static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
16322 { 2, alc662_3ST_ch2_init },
16323 { 6, alc662_3ST_ch6_init },
16324};
16325
16326/*
16327 * 2ch mode
16328 */
16329static struct hda_verb alc662_sixstack_ch6_init[] = {
16330 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
16331 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
16332 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16333 { } /* end */
16334};
16335
16336/*
16337 * 6ch mode
16338 */
16339static struct hda_verb alc662_sixstack_ch8_init[] = {
16340 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16341 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16342 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16343 { } /* end */
16344};
16345
16346static struct hda_channel_mode alc662_5stack_modes[2] = {
16347 { 2, alc662_sixstack_ch6_init },
16348 { 6, alc662_sixstack_ch8_init },
16349};
16350
16351/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
16352 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
16353 */
16354
16355static struct snd_kcontrol_new alc662_base_mixer[] = {
16356 /* output mixer control */
16357 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016358 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016359 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016360 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016361 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
16362 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016363 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
16364 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016365 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16366
16367 /*Input mixer control */
16368 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
16369 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
16370 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
16371 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
16372 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
16373 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
16374 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
16375 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016376 { } /* end */
16377};
16378
16379static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
16380 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016381 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016382 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16383 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16384 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16385 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16386 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16387 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16388 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16389 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16390 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016391 { } /* end */
16392};
16393
16394static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
16395 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016396 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016397 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016398 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016399 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
16400 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016401 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
16402 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016403 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16404 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16405 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16406 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16407 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16408 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16409 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16410 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16411 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016412 { } /* end */
16413};
16414
16415static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
16416 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16417 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010016418 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16419 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016420 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16421 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16422 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16423 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16424 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016425 { } /* end */
16426};
16427
Kailang Yang291702f2007-10-16 14:28:03 +020016428static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020016429 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16430 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang291702f2007-10-16 14:28:03 +020016431
16432 HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
16433 HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16434 HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16435
16436 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
16437 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16438 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16439 { } /* end */
16440};
16441
Kailang Yang8c427222008-01-10 13:03:59 +010016442static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020016443 ALC262_HIPPO_MASTER_SWITCH,
16444 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010016445 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010016446 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
16447 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010016448 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
16449 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16450 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16451 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16452 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16453 { } /* end */
16454};
16455
Kailang Yangf1d4e282008-08-26 14:03:29 +020016456static struct hda_bind_ctls alc663_asus_bind_master_vol = {
16457 .ops = &snd_hda_bind_vol,
16458 .values = {
16459 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
16460 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
16461 0
16462 },
16463};
16464
16465static struct hda_bind_ctls alc663_asus_one_bind_switch = {
16466 .ops = &snd_hda_bind_sw,
16467 .values = {
16468 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
16469 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
16470 0
16471 },
16472};
16473
Kailang Yang6dda9f42008-05-27 12:05:31 +020016474static struct snd_kcontrol_new alc663_m51va_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020016475 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
16476 HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
16477 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16478 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16479 { } /* end */
16480};
16481
16482static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
16483 .ops = &snd_hda_bind_sw,
16484 .values = {
16485 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
16486 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
16487 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
16488 0
16489 },
16490};
16491
16492static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
16493 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
16494 HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
16495 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16496 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16497 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16498 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16499
16500 { } /* end */
16501};
16502
16503static struct hda_bind_ctls alc663_asus_four_bind_switch = {
16504 .ops = &snd_hda_bind_sw,
16505 .values = {
16506 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
16507 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
16508 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
16509 0
16510 },
16511};
16512
16513static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
16514 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
16515 HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
16516 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16517 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16518 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16519 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16520 { } /* end */
16521};
16522
16523static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020016524 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16525 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020016526 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16527 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16528 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16529 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16530 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16531 { } /* end */
16532};
16533
16534static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
16535 .ops = &snd_hda_bind_vol,
16536 .values = {
16537 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
16538 HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
16539 0
16540 },
16541};
16542
16543static struct hda_bind_ctls alc663_asus_two_bind_switch = {
16544 .ops = &snd_hda_bind_sw,
16545 .values = {
16546 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
16547 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
16548 0
16549 },
16550};
16551
16552static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
16553 HDA_BIND_VOL("Master Playback Volume",
16554 &alc663_asus_two_bind_master_vol),
16555 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
16556 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020016557 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
16558 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16559 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020016560 { } /* end */
16561};
16562
16563static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
16564 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
16565 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
16566 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16567 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
16568 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16569 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020016570 { } /* end */
16571};
16572
16573static struct snd_kcontrol_new alc663_g71v_mixer[] = {
16574 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16575 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
16576 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16577 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
16578 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
16579
16580 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16581 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16582 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16583 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16584 { } /* end */
16585};
16586
16587static struct snd_kcontrol_new alc663_g50v_mixer[] = {
16588 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16589 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
16590 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
16591
16592 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16593 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16594 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16595 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16596 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16597 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16598 { } /* end */
16599};
16600
Kailang Yangebb83ee2009-12-17 12:23:00 +010016601static struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = {
16602 .ops = &snd_hda_bind_sw,
16603 .values = {
16604 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
16605 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
16606 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
16607 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
16608 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
16609 0
16610 },
16611};
16612
16613static struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = {
16614 .ops = &snd_hda_bind_sw,
16615 .values = {
16616 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
16617 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
16618 0
16619 },
16620};
16621
16622static struct snd_kcontrol_new alc663_mode7_mixer[] = {
16623 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
16624 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
16625 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
16626 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16627 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
16628 HDA_CODEC_VOLUME("IntMic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16629 HDA_CODEC_MUTE("IntMic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16630 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16631 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16632 { } /* end */
16633};
16634
16635static struct snd_kcontrol_new alc663_mode8_mixer[] = {
16636 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
16637 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
16638 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
16639 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x15, 0x0, HDA_OUTPUT),
16640 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
16641 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16642 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16643 { } /* end */
16644};
16645
16646
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016647static struct snd_kcontrol_new alc662_chmode_mixer[] = {
16648 {
16649 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
16650 .name = "Channel Mode",
16651 .info = alc_ch_mode_info,
16652 .get = alc_ch_mode_get,
16653 .put = alc_ch_mode_put,
16654 },
16655 { } /* end */
16656};
16657
16658static struct hda_verb alc662_init_verbs[] = {
16659 /* ADC: mute amp left and right */
16660 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16661 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016662
Kailang Yangb60dd392007-09-20 12:50:29 +020016663 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16664 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16665 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16666 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16667 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16668 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016669
16670 /* Front Pin: output 0 (0x0c) */
16671 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16672 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16673
16674 /* Rear Pin: output 1 (0x0d) */
16675 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16676 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16677
16678 /* CLFE Pin: output 2 (0x0e) */
16679 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16680 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16681
16682 /* Mic (rear) pin: input vref at 80% */
16683 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16684 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16685 /* Front Mic pin: input vref at 80% */
16686 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16687 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16688 /* Line In pin: input */
16689 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16690 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16691 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16692 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16693 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16694 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16695 /* CD pin widget for input */
16696 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16697
16698 /* FIXME: use matrix-type input source selection */
16699 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
16700 /* Input mixer */
16701 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang291702f2007-10-16 14:28:03 +020016702 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020016703
16704 /* always trun on EAPD */
16705 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16706 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
16707
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016708 { }
16709};
16710
Kailang Yangcec27c82010-02-04 14:18:18 +010016711static struct hda_verb alc663_init_verbs[] = {
16712 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16713 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16714 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16715 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16716 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16717 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16718 { }
16719};
16720
16721static struct hda_verb alc272_init_verbs[] = {
16722 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16723 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16724 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16725 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16726 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16727 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16728 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16729 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16730 { }
16731};
16732
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016733static struct hda_verb alc662_sue_init_verbs[] = {
16734 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
16735 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020016736 {}
16737};
16738
16739static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
16740 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16741 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16742 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016743};
16744
Kailang Yang8c427222008-01-10 13:03:59 +010016745/* Set Unsolicited Event*/
16746static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
16747 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16748 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16749 {}
16750};
16751
Kailang Yang6dda9f42008-05-27 12:05:31 +020016752static struct hda_verb alc663_m51va_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020016753 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16754 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yang6dda9f42008-05-27 12:05:31 +020016755 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16756 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf1d4e282008-08-26 14:03:29 +020016757 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
16758 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16759 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020016760 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16761 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16762 {}
16763};
16764
Kailang Yangf1d4e282008-08-26 14:03:29 +020016765static struct hda_verb alc663_21jd_amic_init_verbs[] = {
16766 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16767 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16768 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
16769 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16770 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16771 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16772 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16773 {}
16774};
16775
16776static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
16777 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16778 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16779 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16780 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
16781 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16782 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16783 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16784 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16785 {}
16786};
16787
16788static struct hda_verb alc663_15jd_amic_init_verbs[] = {
16789 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16790 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16791 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
16792 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16793 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16794 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16795 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16796 {}
16797};
16798
16799static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
16800 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16801 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16802 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16803 {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
16804 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16805 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16806 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
16807 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16808 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16809 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16810 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16811 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16812 {}
16813};
16814
16815static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
16816 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16817 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16818 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16819 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
16820 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16821 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16822 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
16823 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16824 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16825 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16826 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16827 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16828 {}
16829};
16830
Kailang Yang6dda9f42008-05-27 12:05:31 +020016831static struct hda_verb alc663_g71v_init_verbs[] = {
16832 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16833 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
16834 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
16835
16836 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16837 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16838 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
16839
16840 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
16841 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
16842 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
16843 {}
16844};
16845
16846static struct hda_verb alc663_g50v_init_verbs[] = {
16847 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16848 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16849 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
16850
16851 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16852 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16853 {}
16854};
16855
Kailang Yangf1d4e282008-08-26 14:03:29 +020016856static struct hda_verb alc662_ecs_init_verbs[] = {
16857 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
16858 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16859 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16860 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16861 {}
16862};
16863
Kailang Yang622e84c2009-04-21 07:39:04 +020016864static struct hda_verb alc272_dell_zm1_init_verbs[] = {
16865 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16866 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16867 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16868 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16869 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16870 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16871 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
16872 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16873 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
16874 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16875 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16876 {}
16877};
16878
16879static struct hda_verb alc272_dell_init_verbs[] = {
16880 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16881 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16882 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16883 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16884 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16885 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16886 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
16887 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16888 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
16889 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16890 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16891 {}
16892};
16893
Kailang Yangebb83ee2009-12-17 12:23:00 +010016894static struct hda_verb alc663_mode7_init_verbs[] = {
16895 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16896 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16897 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16898 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16899 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16900 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16901 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
16902 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16903 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16904 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
16905 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16906 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
16907 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16908 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16909 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16910 {}
16911};
16912
16913static struct hda_verb alc663_mode8_init_verbs[] = {
16914 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16915 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16916 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16917 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
16918 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16919 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16920 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16921 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16922 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16923 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16924 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
16925 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16926 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
16927 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16928 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16929 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16930 {}
16931};
16932
Kailang Yangf1d4e282008-08-26 14:03:29 +020016933static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
16934 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
16935 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
16936 { } /* end */
16937};
16938
Kailang Yang622e84c2009-04-21 07:39:04 +020016939static struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
16940 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
16941 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
16942 { } /* end */
16943};
16944
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016945static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
16946{
16947 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016948 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016949
Wu Fengguang864f92b2009-11-18 12:38:02 +080016950 present = snd_hda_jack_detect(codec, 0x14);
Takashi Iwai47fd8302007-08-10 17:11:07 +020016951 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080016952
Takashi Iwai47fd8302007-08-10 17:11:07 +020016953 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
16954 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016955}
16956
16957static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
16958{
16959 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016960 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016961
Wu Fengguang864f92b2009-11-18 12:38:02 +080016962 present = snd_hda_jack_detect(codec, 0x1b);
Takashi Iwai47fd8302007-08-10 17:11:07 +020016963 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080016964
Takashi Iwai47fd8302007-08-10 17:11:07 +020016965 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
16966 HDA_AMP_MUTE, bits);
16967 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
16968 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016969}
16970
16971static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
16972 unsigned int res)
16973{
16974 if ((res >> 26) == ALC880_HP_EVENT)
16975 alc662_lenovo_101e_all_automute(codec);
16976 if ((res >> 26) == ALC880_FRONT_EVENT)
16977 alc662_lenovo_101e_ispeaker_automute(codec);
16978}
16979
Kailang Yang291702f2007-10-16 14:28:03 +020016980/* unsolicited event for HP jack sensing */
16981static void alc662_eeepc_unsol_event(struct hda_codec *codec,
16982 unsigned int res)
16983{
Kailang Yang291702f2007-10-16 14:28:03 +020016984 if ((res >> 26) == ALC880_MIC_EVENT)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016985 alc_mic_automute(codec);
Takashi Iwai42171c12009-05-08 14:11:43 +020016986 else
16987 alc262_hippo_unsol_event(codec, res);
Kailang Yang291702f2007-10-16 14:28:03 +020016988}
16989
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016990static void alc662_eeepc_setup(struct hda_codec *codec)
Kailang Yang291702f2007-10-16 14:28:03 +020016991{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016992 struct alc_spec *spec = codec->spec;
16993
16994 alc262_hippo1_setup(codec);
16995 spec->ext_mic.pin = 0x18;
16996 spec->ext_mic.mux_idx = 0;
16997 spec->int_mic.pin = 0x19;
16998 spec->int_mic.mux_idx = 1;
16999 spec->auto_mic = 1;
Kailang Yang291702f2007-10-16 14:28:03 +020017000}
17001
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017002static void alc662_eeepc_inithook(struct hda_codec *codec)
17003{
17004 alc262_hippo_automute(codec);
17005 alc_mic_automute(codec);
17006}
17007
17008static void alc662_eeepc_ep20_setup(struct hda_codec *codec)
Kailang Yang8c427222008-01-10 13:03:59 +010017009{
Takashi Iwai42171c12009-05-08 14:11:43 +020017010 struct alc_spec *spec = codec->spec;
17011
17012 spec->autocfg.hp_pins[0] = 0x14;
17013 spec->autocfg.speaker_pins[0] = 0x1b;
Kailang Yang8c427222008-01-10 13:03:59 +010017014}
17015
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017016#define alc662_eeepc_ep20_inithook alc262_hippo_master_update
17017
Kailang Yang6dda9f42008-05-27 12:05:31 +020017018static void alc663_m51va_speaker_automute(struct hda_codec *codec)
17019{
17020 unsigned int present;
17021 unsigned char bits;
17022
Wu Fengguang864f92b2009-11-18 12:38:02 +080017023 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017024 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yangf1d4e282008-08-26 14:03:29 +020017025 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
17026 AMP_IN_MUTE(0), bits);
17027 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
17028 AMP_IN_MUTE(0), bits);
17029}
17030
17031static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
17032{
17033 unsigned int present;
17034 unsigned char bits;
17035
Wu Fengguang864f92b2009-11-18 12:38:02 +080017036 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017037 bits = present ? HDA_AMP_MUTE : 0;
17038 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
17039 AMP_IN_MUTE(0), bits);
17040 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
17041 AMP_IN_MUTE(0), bits);
17042 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
17043 AMP_IN_MUTE(0), bits);
17044 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
17045 AMP_IN_MUTE(0), bits);
17046}
17047
17048static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
17049{
17050 unsigned int present;
17051 unsigned char bits;
17052
Wu Fengguang864f92b2009-11-18 12:38:02 +080017053 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017054 bits = present ? HDA_AMP_MUTE : 0;
17055 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
17056 AMP_IN_MUTE(0), bits);
17057 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
17058 AMP_IN_MUTE(0), bits);
17059 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
17060 AMP_IN_MUTE(0), bits);
17061 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
17062 AMP_IN_MUTE(0), bits);
17063}
17064
17065static void alc662_f5z_speaker_automute(struct hda_codec *codec)
17066{
17067 unsigned int present;
17068 unsigned char bits;
17069
Wu Fengguang864f92b2009-11-18 12:38:02 +080017070 present = snd_hda_jack_detect(codec, 0x1b);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017071 bits = present ? 0 : PIN_OUT;
17072 snd_hda_codec_write(codec, 0x14, 0,
17073 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
17074}
17075
17076static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
17077{
17078 unsigned int present1, present2;
17079
Wu Fengguang864f92b2009-11-18 12:38:02 +080017080 present1 = snd_hda_jack_detect(codec, 0x21);
17081 present2 = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017082
17083 if (present1 || present2) {
17084 snd_hda_codec_write_cache(codec, 0x14, 0,
17085 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17086 } else {
17087 snd_hda_codec_write_cache(codec, 0x14, 0,
17088 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17089 }
17090}
17091
17092static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
17093{
17094 unsigned int present1, present2;
17095
Wu Fengguang864f92b2009-11-18 12:38:02 +080017096 present1 = snd_hda_jack_detect(codec, 0x1b);
17097 present2 = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017098
17099 if (present1 || present2) {
17100 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
17101 AMP_IN_MUTE(0), AMP_IN_MUTE(0));
17102 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
17103 AMP_IN_MUTE(0), AMP_IN_MUTE(0));
17104 } else {
17105 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
17106 AMP_IN_MUTE(0), 0);
17107 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
17108 AMP_IN_MUTE(0), 0);
17109 }
Kailang Yang6dda9f42008-05-27 12:05:31 +020017110}
17111
Kailang Yangebb83ee2009-12-17 12:23:00 +010017112static void alc663_two_hp_m7_speaker_automute(struct hda_codec *codec)
17113{
17114 unsigned int present1, present2;
17115
17116 present1 = snd_hda_codec_read(codec, 0x1b, 0,
17117 AC_VERB_GET_PIN_SENSE, 0)
17118 & AC_PINSENSE_PRESENCE;
17119 present2 = snd_hda_codec_read(codec, 0x21, 0,
17120 AC_VERB_GET_PIN_SENSE, 0)
17121 & AC_PINSENSE_PRESENCE;
17122
17123 if (present1 || present2) {
17124 snd_hda_codec_write_cache(codec, 0x14, 0,
17125 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17126 snd_hda_codec_write_cache(codec, 0x17, 0,
17127 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17128 } else {
17129 snd_hda_codec_write_cache(codec, 0x14, 0,
17130 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17131 snd_hda_codec_write_cache(codec, 0x17, 0,
17132 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17133 }
17134}
17135
17136static void alc663_two_hp_m8_speaker_automute(struct hda_codec *codec)
17137{
17138 unsigned int present1, present2;
17139
17140 present1 = snd_hda_codec_read(codec, 0x21, 0,
17141 AC_VERB_GET_PIN_SENSE, 0)
17142 & AC_PINSENSE_PRESENCE;
17143 present2 = snd_hda_codec_read(codec, 0x15, 0,
17144 AC_VERB_GET_PIN_SENSE, 0)
17145 & AC_PINSENSE_PRESENCE;
17146
17147 if (present1 || present2) {
17148 snd_hda_codec_write_cache(codec, 0x14, 0,
17149 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17150 snd_hda_codec_write_cache(codec, 0x17, 0,
17151 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17152 } else {
17153 snd_hda_codec_write_cache(codec, 0x14, 0,
17154 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17155 snd_hda_codec_write_cache(codec, 0x17, 0,
17156 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17157 }
17158}
17159
Kailang Yang6dda9f42008-05-27 12:05:31 +020017160static void alc663_m51va_unsol_event(struct hda_codec *codec,
17161 unsigned int res)
17162{
17163 switch (res >> 26) {
17164 case ALC880_HP_EVENT:
17165 alc663_m51va_speaker_automute(codec);
17166 break;
17167 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017168 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017169 break;
17170 }
17171}
17172
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017173static void alc663_m51va_setup(struct hda_codec *codec)
17174{
17175 struct alc_spec *spec = codec->spec;
17176 spec->ext_mic.pin = 0x18;
17177 spec->ext_mic.mux_idx = 0;
17178 spec->int_mic.pin = 0x12;
Kailang Yangebb83ee2009-12-17 12:23:00 +010017179 spec->int_mic.mux_idx = 9;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017180 spec->auto_mic = 1;
17181}
17182
Kailang Yang6dda9f42008-05-27 12:05:31 +020017183static void alc663_m51va_inithook(struct hda_codec *codec)
17184{
17185 alc663_m51va_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017186 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017187}
17188
Kailang Yangf1d4e282008-08-26 14:03:29 +020017189/* ***************** Mode1 ******************************/
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017190#define alc663_mode1_unsol_event alc663_m51va_unsol_event
Kailang Yangebb83ee2009-12-17 12:23:00 +010017191
17192static void alc663_mode1_setup(struct hda_codec *codec)
17193{
17194 struct alc_spec *spec = codec->spec;
17195 spec->ext_mic.pin = 0x18;
17196 spec->ext_mic.mux_idx = 0;
17197 spec->int_mic.pin = 0x19;
17198 spec->int_mic.mux_idx = 1;
17199 spec->auto_mic = 1;
17200}
17201
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017202#define alc663_mode1_inithook alc663_m51va_inithook
Kailang Yangf1d4e282008-08-26 14:03:29 +020017203
Kailang Yangf1d4e282008-08-26 14:03:29 +020017204/* ***************** Mode2 ******************************/
17205static void alc662_mode2_unsol_event(struct hda_codec *codec,
17206 unsigned int res)
17207{
17208 switch (res >> 26) {
17209 case ALC880_HP_EVENT:
17210 alc662_f5z_speaker_automute(codec);
17211 break;
17212 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017213 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017214 break;
17215 }
17216}
17217
Kailang Yangebb83ee2009-12-17 12:23:00 +010017218#define alc662_mode2_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017219
Kailang Yangf1d4e282008-08-26 14:03:29 +020017220static void alc662_mode2_inithook(struct hda_codec *codec)
17221{
17222 alc662_f5z_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017223 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017224}
17225/* ***************** Mode3 ******************************/
17226static void alc663_mode3_unsol_event(struct hda_codec *codec,
17227 unsigned int res)
17228{
17229 switch (res >> 26) {
17230 case ALC880_HP_EVENT:
17231 alc663_two_hp_m1_speaker_automute(codec);
17232 break;
17233 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017234 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017235 break;
17236 }
17237}
17238
Kailang Yangebb83ee2009-12-17 12:23:00 +010017239#define alc663_mode3_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017240
Kailang Yangf1d4e282008-08-26 14:03:29 +020017241static void alc663_mode3_inithook(struct hda_codec *codec)
17242{
17243 alc663_two_hp_m1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017244 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017245}
17246/* ***************** Mode4 ******************************/
17247static void alc663_mode4_unsol_event(struct hda_codec *codec,
17248 unsigned int res)
17249{
17250 switch (res >> 26) {
17251 case ALC880_HP_EVENT:
17252 alc663_21jd_two_speaker_automute(codec);
17253 break;
17254 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017255 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017256 break;
17257 }
17258}
17259
Kailang Yangebb83ee2009-12-17 12:23:00 +010017260#define alc663_mode4_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017261
Kailang Yangf1d4e282008-08-26 14:03:29 +020017262static void alc663_mode4_inithook(struct hda_codec *codec)
17263{
17264 alc663_21jd_two_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017265 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017266}
17267/* ***************** Mode5 ******************************/
17268static void alc663_mode5_unsol_event(struct hda_codec *codec,
17269 unsigned int res)
17270{
17271 switch (res >> 26) {
17272 case ALC880_HP_EVENT:
17273 alc663_15jd_two_speaker_automute(codec);
17274 break;
17275 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017276 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017277 break;
17278 }
17279}
17280
Kailang Yangebb83ee2009-12-17 12:23:00 +010017281#define alc663_mode5_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017282
Kailang Yangf1d4e282008-08-26 14:03:29 +020017283static void alc663_mode5_inithook(struct hda_codec *codec)
17284{
17285 alc663_15jd_two_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017286 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017287}
17288/* ***************** Mode6 ******************************/
17289static void alc663_mode6_unsol_event(struct hda_codec *codec,
17290 unsigned int res)
17291{
17292 switch (res >> 26) {
17293 case ALC880_HP_EVENT:
17294 alc663_two_hp_m2_speaker_automute(codec);
17295 break;
17296 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017297 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017298 break;
17299 }
17300}
17301
Kailang Yangebb83ee2009-12-17 12:23:00 +010017302#define alc663_mode6_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017303
Kailang Yangf1d4e282008-08-26 14:03:29 +020017304static void alc663_mode6_inithook(struct hda_codec *codec)
17305{
17306 alc663_two_hp_m2_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017307 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017308}
17309
Kailang Yangebb83ee2009-12-17 12:23:00 +010017310/* ***************** Mode7 ******************************/
17311static void alc663_mode7_unsol_event(struct hda_codec *codec,
17312 unsigned int res)
17313{
17314 switch (res >> 26) {
17315 case ALC880_HP_EVENT:
17316 alc663_two_hp_m7_speaker_automute(codec);
17317 break;
17318 case ALC880_MIC_EVENT:
17319 alc_mic_automute(codec);
17320 break;
17321 }
17322}
17323
17324#define alc663_mode7_setup alc663_mode1_setup
17325
17326static void alc663_mode7_inithook(struct hda_codec *codec)
17327{
17328 alc663_two_hp_m7_speaker_automute(codec);
17329 alc_mic_automute(codec);
17330}
17331
17332/* ***************** Mode8 ******************************/
17333static void alc663_mode8_unsol_event(struct hda_codec *codec,
17334 unsigned int res)
17335{
17336 switch (res >> 26) {
17337 case ALC880_HP_EVENT:
17338 alc663_two_hp_m8_speaker_automute(codec);
17339 break;
17340 case ALC880_MIC_EVENT:
17341 alc_mic_automute(codec);
17342 break;
17343 }
17344}
17345
17346#define alc663_mode8_setup alc663_m51va_setup
17347
17348static void alc663_mode8_inithook(struct hda_codec *codec)
17349{
17350 alc663_two_hp_m8_speaker_automute(codec);
17351 alc_mic_automute(codec);
17352}
17353
Kailang Yang6dda9f42008-05-27 12:05:31 +020017354static void alc663_g71v_hp_automute(struct hda_codec *codec)
17355{
17356 unsigned int present;
17357 unsigned char bits;
17358
Wu Fengguang864f92b2009-11-18 12:38:02 +080017359 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017360 bits = present ? HDA_AMP_MUTE : 0;
17361 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
17362 HDA_AMP_MUTE, bits);
17363 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
17364 HDA_AMP_MUTE, bits);
17365}
17366
17367static void alc663_g71v_front_automute(struct hda_codec *codec)
17368{
17369 unsigned int present;
17370 unsigned char bits;
17371
Wu Fengguang864f92b2009-11-18 12:38:02 +080017372 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017373 bits = present ? HDA_AMP_MUTE : 0;
17374 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
17375 HDA_AMP_MUTE, bits);
17376}
17377
17378static void alc663_g71v_unsol_event(struct hda_codec *codec,
17379 unsigned int res)
17380{
17381 switch (res >> 26) {
17382 case ALC880_HP_EVENT:
17383 alc663_g71v_hp_automute(codec);
17384 break;
17385 case ALC880_FRONT_EVENT:
17386 alc663_g71v_front_automute(codec);
17387 break;
17388 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017389 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017390 break;
17391 }
17392}
17393
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017394#define alc663_g71v_setup alc663_m51va_setup
17395
Kailang Yang6dda9f42008-05-27 12:05:31 +020017396static void alc663_g71v_inithook(struct hda_codec *codec)
17397{
17398 alc663_g71v_front_automute(codec);
17399 alc663_g71v_hp_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017400 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017401}
17402
17403static void alc663_g50v_unsol_event(struct hda_codec *codec,
17404 unsigned int res)
17405{
17406 switch (res >> 26) {
17407 case ALC880_HP_EVENT:
17408 alc663_m51va_speaker_automute(codec);
17409 break;
17410 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017411 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017412 break;
17413 }
17414}
17415
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017416#define alc663_g50v_setup alc663_m51va_setup
17417
Kailang Yang6dda9f42008-05-27 12:05:31 +020017418static void alc663_g50v_inithook(struct hda_codec *codec)
17419{
17420 alc663_m51va_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017421 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017422}
17423
Kailang Yangf1d4e282008-08-26 14:03:29 +020017424static struct snd_kcontrol_new alc662_ecs_mixer[] = {
17425 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020017426 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017427
17428 HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT),
17429 HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
17430 HDA_CODEC_MUTE("e-Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
17431
17432 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
17433 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17434 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17435 { } /* end */
17436};
17437
Chris Pockelé9541ba12009-05-12 08:08:53 +020017438static struct snd_kcontrol_new alc272_nc10_mixer[] = {
17439 /* Master Playback automatically created from Speaker and Headphone */
17440 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17441 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17442 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17443 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17444
17445 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17446 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17447 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
17448
17449 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17450 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17451 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
17452 { } /* end */
17453};
17454
Takashi Iwaicb53c622007-08-10 17:21:45 +020017455#ifdef CONFIG_SND_HDA_POWER_SAVE
17456#define alc662_loopbacks alc880_loopbacks
17457#endif
17458
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017459
Sasha Alexandrdef319f2009-06-16 16:00:15 -040017460/* pcm configuration: identical with ALC880 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017461#define alc662_pcm_analog_playback alc880_pcm_analog_playback
17462#define alc662_pcm_analog_capture alc880_pcm_analog_capture
17463#define alc662_pcm_digital_playback alc880_pcm_digital_playback
17464#define alc662_pcm_digital_capture alc880_pcm_digital_capture
17465
17466/*
17467 * configuration and preset
17468 */
17469static const char *alc662_models[ALC662_MODEL_LAST] = {
17470 [ALC662_3ST_2ch_DIG] = "3stack-dig",
17471 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
17472 [ALC662_3ST_6ch] = "3stack-6ch",
17473 [ALC662_5ST_DIG] = "6stack-dig",
17474 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020017475 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010017476 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangf1d4e282008-08-26 14:03:29 +020017477 [ALC662_ECS] = "ecs",
Kailang Yang6dda9f42008-05-27 12:05:31 +020017478 [ALC663_ASUS_M51VA] = "m51va",
17479 [ALC663_ASUS_G71V] = "g71v",
17480 [ALC663_ASUS_H13] = "h13",
17481 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangf1d4e282008-08-26 14:03:29 +020017482 [ALC663_ASUS_MODE1] = "asus-mode1",
17483 [ALC662_ASUS_MODE2] = "asus-mode2",
17484 [ALC663_ASUS_MODE3] = "asus-mode3",
17485 [ALC663_ASUS_MODE4] = "asus-mode4",
17486 [ALC663_ASUS_MODE5] = "asus-mode5",
17487 [ALC663_ASUS_MODE6] = "asus-mode6",
Kailang Yangebb83ee2009-12-17 12:23:00 +010017488 [ALC663_ASUS_MODE7] = "asus-mode7",
17489 [ALC663_ASUS_MODE8] = "asus-mode8",
Takashi Iwai01f2bd42009-05-11 08:12:43 +020017490 [ALC272_DELL] = "dell",
17491 [ALC272_DELL_ZM1] = "dell-zm1",
Chris Pockelé9541ba12009-05-12 08:08:53 +020017492 [ALC272_SAMSUNG_NC10] = "samsung-nc10",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017493 [ALC662_AUTO] = "auto",
17494};
17495
17496static struct snd_pci_quirk alc662_cfg_tbl[] = {
Takashi Iwaidea0a502009-02-09 17:14:52 +010017497 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
Kailang Yang622e84c2009-04-21 07:39:04 +020017498 SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
17499 SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017500 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
17501 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
Kailang Yangcec27c82010-02-04 14:18:18 +010017502 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017503 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
17504 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
17505 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
17506 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
Kailang Yangebb83ee2009-12-17 12:23:00 +010017507 SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC663_ASUS_MODE1),
17508 SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017509 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010017510 SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC663_ASUS_MODE7),
17511 SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC663_ASUS_MODE7),
17512 SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC663_ASUS_MODE8),
17513 SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC663_ASUS_MODE3),
17514 SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017515 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010017516 SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_ASUS_MODE2),
17517 SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017518 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
17519 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
17520 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
17521 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010017522 SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020017523 SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3),
17524 SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA),
17525 SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017526 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
17527 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
17528 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
17529 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020017530 SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017531 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
17532 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017533 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017534 /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/
17535 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
17536 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020017537 SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1),
Kailang Yangcec27c82010-02-04 14:18:18 +010017538 SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020017539 SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1),
17540 SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017541 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
17542 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
17543 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020017544 SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017545 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
17546 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020017547 SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017548 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
Kailang Yang80ffe862008-10-15 11:23:27 +020017549 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017550 /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/
17551 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
17552 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020017553 SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017554 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
17555 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010017556 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020017557 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010017558 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017559 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
Herton Ronaldo Krzesinski95fe5f22008-09-26 23:48:45 -030017560 SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
17561 ALC662_3ST_6ch_DIG),
Takashi Iwai4dee8ba2010-01-13 17:20:08 +010017562 SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO),
Chris Pockelé9541ba12009-05-12 08:08:53 +020017563 SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
Herton Ronaldo Krzesinskicb559742008-09-26 23:47:45 -030017564 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
17565 ALC662_3ST_6ch_DIG),
Vedran Miletic19c009a2008-09-29 20:29:25 +020017566 SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
Takashi Iwai5bd37292009-04-21 18:36:30 +020017567 SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017568 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Takashi Iwai238713d2008-10-05 10:57:39 +020017569 SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
Vedran Miletic19c009a2008-09-29 20:29:25 +020017570 ALC662_3ST_6ch_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017571 SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
17572 ALC663_ASUS_H13),
David Santinoli7aee6742009-12-09 12:34:26 +010017573 SND_PCI_QUIRK(0x8086, 0xd604, "Intel mobo", ALC662_3ST_2ch_DIG),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017574 {}
17575};
17576
17577static struct alc_config_preset alc662_presets[] = {
17578 [ALC662_3ST_2ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017579 .mixers = { alc662_3ST_2ch_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017580 .init_verbs = { alc662_init_verbs },
17581 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17582 .dac_nids = alc662_dac_nids,
17583 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017584 .dig_in_nid = ALC662_DIGIN_NID,
17585 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17586 .channel_mode = alc662_3ST_2ch_modes,
17587 .input_mux = &alc662_capture_source,
17588 },
17589 [ALC662_3ST_6ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017590 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017591 .init_verbs = { alc662_init_verbs },
17592 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17593 .dac_nids = alc662_dac_nids,
17594 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017595 .dig_in_nid = ALC662_DIGIN_NID,
17596 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
17597 .channel_mode = alc662_3ST_6ch_modes,
17598 .need_dac_fix = 1,
17599 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017600 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017601 [ALC662_3ST_6ch] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017602 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017603 .init_verbs = { alc662_init_verbs },
17604 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17605 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017606 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
17607 .channel_mode = alc662_3ST_6ch_modes,
17608 .need_dac_fix = 1,
17609 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017610 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017611 [ALC662_5ST_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017612 .mixers = { alc662_base_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017613 .init_verbs = { alc662_init_verbs },
17614 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17615 .dac_nids = alc662_dac_nids,
17616 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017617 .dig_in_nid = ALC662_DIGIN_NID,
17618 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
17619 .channel_mode = alc662_5stack_modes,
17620 .input_mux = &alc662_capture_source,
17621 },
17622 [ALC662_LENOVO_101E] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017623 .mixers = { alc662_lenovo_101e_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017624 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
17625 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17626 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017627 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17628 .channel_mode = alc662_3ST_2ch_modes,
17629 .input_mux = &alc662_lenovo_101e_capture_source,
17630 .unsol_event = alc662_lenovo_101e_unsol_event,
17631 .init_hook = alc662_lenovo_101e_all_automute,
17632 },
Kailang Yang291702f2007-10-16 14:28:03 +020017633 [ALC662_ASUS_EEEPC_P701] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017634 .mixers = { alc662_eeepc_p701_mixer },
Kailang Yang291702f2007-10-16 14:28:03 +020017635 .init_verbs = { alc662_init_verbs,
17636 alc662_eeepc_sue_init_verbs },
17637 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17638 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020017639 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17640 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang291702f2007-10-16 14:28:03 +020017641 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017642 .setup = alc662_eeepc_setup,
Kailang Yang291702f2007-10-16 14:28:03 +020017643 .init_hook = alc662_eeepc_inithook,
17644 },
Kailang Yang8c427222008-01-10 13:03:59 +010017645 [ALC662_ASUS_EEEPC_EP20] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017646 .mixers = { alc662_eeepc_ep20_mixer,
Kailang Yang8c427222008-01-10 13:03:59 +010017647 alc662_chmode_mixer },
17648 .init_verbs = { alc662_init_verbs,
17649 alc662_eeepc_ep20_sue_init_verbs },
17650 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17651 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010017652 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
17653 .channel_mode = alc662_3ST_6ch_modes,
17654 .input_mux = &alc662_lenovo_101e_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020017655 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017656 .setup = alc662_eeepc_ep20_setup,
Kailang Yang8c427222008-01-10 13:03:59 +010017657 .init_hook = alc662_eeepc_ep20_inithook,
17658 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020017659 [ALC662_ECS] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017660 .mixers = { alc662_ecs_mixer },
Kailang Yangf1d4e282008-08-26 14:03:29 +020017661 .init_verbs = { alc662_init_verbs,
17662 alc662_ecs_init_verbs },
17663 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17664 .dac_nids = alc662_dac_nids,
17665 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17666 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017667 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017668 .setup = alc662_eeepc_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017669 .init_hook = alc662_eeepc_inithook,
17670 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020017671 [ALC663_ASUS_M51VA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017672 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020017673 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
17674 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17675 .dac_nids = alc662_dac_nids,
17676 .dig_out_nid = ALC662_DIGOUT_NID,
17677 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17678 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020017679 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017680 .setup = alc663_m51va_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020017681 .init_hook = alc663_m51va_inithook,
17682 },
17683 [ALC663_ASUS_G71V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017684 .mixers = { alc663_g71v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020017685 .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
17686 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17687 .dac_nids = alc662_dac_nids,
17688 .dig_out_nid = ALC662_DIGOUT_NID,
17689 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17690 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020017691 .unsol_event = alc663_g71v_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017692 .setup = alc663_g71v_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020017693 .init_hook = alc663_g71v_inithook,
17694 },
17695 [ALC663_ASUS_H13] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017696 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020017697 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
17698 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17699 .dac_nids = alc662_dac_nids,
17700 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17701 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020017702 .unsol_event = alc663_m51va_unsol_event,
17703 .init_hook = alc663_m51va_inithook,
17704 },
17705 [ALC663_ASUS_G50V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017706 .mixers = { alc663_g50v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020017707 .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
17708 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17709 .dac_nids = alc662_dac_nids,
17710 .dig_out_nid = ALC662_DIGOUT_NID,
17711 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
17712 .channel_mode = alc662_3ST_6ch_modes,
17713 .input_mux = &alc663_capture_source,
17714 .unsol_event = alc663_g50v_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017715 .setup = alc663_g50v_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020017716 .init_hook = alc663_g50v_inithook,
17717 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020017718 [ALC663_ASUS_MODE1] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017719 .mixers = { alc663_m51va_mixer },
17720 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017721 .init_verbs = { alc662_init_verbs,
17722 alc663_21jd_amic_init_verbs },
17723 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17724 .hp_nid = 0x03,
17725 .dac_nids = alc662_dac_nids,
17726 .dig_out_nid = ALC662_DIGOUT_NID,
17727 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17728 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017729 .unsol_event = alc663_mode1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017730 .setup = alc663_mode1_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017731 .init_hook = alc663_mode1_inithook,
17732 },
17733 [ALC662_ASUS_MODE2] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017734 .mixers = { alc662_1bjd_mixer },
17735 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017736 .init_verbs = { alc662_init_verbs,
17737 alc662_1bjd_amic_init_verbs },
17738 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17739 .dac_nids = alc662_dac_nids,
17740 .dig_out_nid = ALC662_DIGOUT_NID,
17741 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17742 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017743 .unsol_event = alc662_mode2_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017744 .setup = alc662_mode2_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017745 .init_hook = alc662_mode2_inithook,
17746 },
17747 [ALC663_ASUS_MODE3] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017748 .mixers = { alc663_two_hp_m1_mixer },
17749 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017750 .init_verbs = { alc662_init_verbs,
17751 alc663_two_hp_amic_m1_init_verbs },
17752 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17753 .hp_nid = 0x03,
17754 .dac_nids = alc662_dac_nids,
17755 .dig_out_nid = ALC662_DIGOUT_NID,
17756 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17757 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017758 .unsol_event = alc663_mode3_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017759 .setup = alc663_mode3_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017760 .init_hook = alc663_mode3_inithook,
17761 },
17762 [ALC663_ASUS_MODE4] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017763 .mixers = { alc663_asus_21jd_clfe_mixer },
17764 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017765 .init_verbs = { alc662_init_verbs,
17766 alc663_21jd_amic_init_verbs},
17767 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17768 .hp_nid = 0x03,
17769 .dac_nids = alc662_dac_nids,
17770 .dig_out_nid = ALC662_DIGOUT_NID,
17771 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17772 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017773 .unsol_event = alc663_mode4_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017774 .setup = alc663_mode4_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017775 .init_hook = alc663_mode4_inithook,
17776 },
17777 [ALC663_ASUS_MODE5] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017778 .mixers = { alc663_asus_15jd_clfe_mixer },
17779 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017780 .init_verbs = { alc662_init_verbs,
17781 alc663_15jd_amic_init_verbs },
17782 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17783 .hp_nid = 0x03,
17784 .dac_nids = alc662_dac_nids,
17785 .dig_out_nid = ALC662_DIGOUT_NID,
17786 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17787 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017788 .unsol_event = alc663_mode5_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017789 .setup = alc663_mode5_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017790 .init_hook = alc663_mode5_inithook,
17791 },
17792 [ALC663_ASUS_MODE6] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017793 .mixers = { alc663_two_hp_m2_mixer },
17794 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017795 .init_verbs = { alc662_init_verbs,
17796 alc663_two_hp_amic_m2_init_verbs },
17797 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17798 .hp_nid = 0x03,
17799 .dac_nids = alc662_dac_nids,
17800 .dig_out_nid = ALC662_DIGOUT_NID,
17801 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17802 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017803 .unsol_event = alc663_mode6_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017804 .setup = alc663_mode6_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017805 .init_hook = alc663_mode6_inithook,
17806 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010017807 [ALC663_ASUS_MODE7] = {
17808 .mixers = { alc663_mode7_mixer },
17809 .cap_mixer = alc662_auto_capture_mixer,
17810 .init_verbs = { alc662_init_verbs,
17811 alc663_mode7_init_verbs },
17812 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17813 .hp_nid = 0x03,
17814 .dac_nids = alc662_dac_nids,
17815 .dig_out_nid = ALC662_DIGOUT_NID,
17816 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17817 .channel_mode = alc662_3ST_2ch_modes,
17818 .unsol_event = alc663_mode7_unsol_event,
17819 .setup = alc663_mode7_setup,
17820 .init_hook = alc663_mode7_inithook,
17821 },
17822 [ALC663_ASUS_MODE8] = {
17823 .mixers = { alc663_mode8_mixer },
17824 .cap_mixer = alc662_auto_capture_mixer,
17825 .init_verbs = { alc662_init_verbs,
17826 alc663_mode8_init_verbs },
17827 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17828 .hp_nid = 0x03,
17829 .dac_nids = alc662_dac_nids,
17830 .dig_out_nid = ALC662_DIGOUT_NID,
17831 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17832 .channel_mode = alc662_3ST_2ch_modes,
17833 .unsol_event = alc663_mode8_unsol_event,
17834 .setup = alc663_mode8_setup,
17835 .init_hook = alc663_mode8_inithook,
17836 },
Kailang Yang622e84c2009-04-21 07:39:04 +020017837 [ALC272_DELL] = {
17838 .mixers = { alc663_m51va_mixer },
17839 .cap_mixer = alc272_auto_capture_mixer,
17840 .init_verbs = { alc662_init_verbs, alc272_dell_init_verbs },
17841 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
17842 .dac_nids = alc662_dac_nids,
17843 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17844 .adc_nids = alc272_adc_nids,
17845 .num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
17846 .capsrc_nids = alc272_capsrc_nids,
17847 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang622e84c2009-04-21 07:39:04 +020017848 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017849 .setup = alc663_m51va_setup,
Kailang Yang622e84c2009-04-21 07:39:04 +020017850 .init_hook = alc663_m51va_inithook,
17851 },
17852 [ALC272_DELL_ZM1] = {
17853 .mixers = { alc663_m51va_mixer },
17854 .cap_mixer = alc662_auto_capture_mixer,
17855 .init_verbs = { alc662_init_verbs, alc272_dell_zm1_init_verbs },
17856 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
17857 .dac_nids = alc662_dac_nids,
17858 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17859 .adc_nids = alc662_adc_nids,
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017860 .num_adc_nids = 1,
Kailang Yang622e84c2009-04-21 07:39:04 +020017861 .capsrc_nids = alc662_capsrc_nids,
17862 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang622e84c2009-04-21 07:39:04 +020017863 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017864 .setup = alc663_m51va_setup,
Kailang Yang622e84c2009-04-21 07:39:04 +020017865 .init_hook = alc663_m51va_inithook,
17866 },
Chris Pockelé9541ba12009-05-12 08:08:53 +020017867 [ALC272_SAMSUNG_NC10] = {
17868 .mixers = { alc272_nc10_mixer },
17869 .init_verbs = { alc662_init_verbs,
17870 alc663_21jd_amic_init_verbs },
17871 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
17872 .dac_nids = alc272_dac_nids,
17873 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17874 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017875 /*.input_mux = &alc272_nc10_capture_source,*/
Chris Pockelé9541ba12009-05-12 08:08:53 +020017876 .unsol_event = alc663_mode4_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017877 .setup = alc663_mode4_setup,
Chris Pockelé9541ba12009-05-12 08:08:53 +020017878 .init_hook = alc663_mode4_inithook,
17879 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017880};
17881
17882
17883/*
17884 * BIOS auto configuration
17885 */
17886
Takashi Iwai7085ec12009-10-02 09:03:58 +020017887/* convert from MIX nid to DAC */
17888static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid)
17889{
17890 if (nid == 0x0f)
17891 return 0x02;
17892 else if (nid >= 0x0c && nid <= 0x0e)
17893 return nid - 0x0c + 0x02;
17894 else
17895 return 0;
17896}
17897
17898/* get MIX nid connected to the given pin targeted to DAC */
17899static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
17900 hda_nid_t dac)
17901{
17902 hda_nid_t mix[4];
17903 int i, num;
17904
17905 num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
17906 for (i = 0; i < num; i++) {
17907 if (alc662_mix_to_dac(mix[i]) == dac)
17908 return mix[i];
17909 }
17910 return 0;
17911}
17912
17913/* look for an empty DAC slot */
17914static hda_nid_t alc662_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
17915{
17916 struct alc_spec *spec = codec->spec;
17917 hda_nid_t srcs[5];
17918 int i, j, num;
17919
17920 num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
17921 if (num < 0)
17922 return 0;
17923 for (i = 0; i < num; i++) {
17924 hda_nid_t nid = alc662_mix_to_dac(srcs[i]);
17925 if (!nid)
17926 continue;
17927 for (j = 0; j < spec->multiout.num_dacs; j++)
17928 if (spec->multiout.dac_nids[j] == nid)
17929 break;
17930 if (j >= spec->multiout.num_dacs)
17931 return nid;
17932 }
17933 return 0;
17934}
17935
17936/* fill in the dac_nids table from the parsed pin configuration */
17937static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
17938 const struct auto_pin_cfg *cfg)
17939{
17940 struct alc_spec *spec = codec->spec;
17941 int i;
17942 hda_nid_t dac;
17943
17944 spec->multiout.dac_nids = spec->private_dac_nids;
17945 for (i = 0; i < cfg->line_outs; i++) {
17946 dac = alc662_look_for_dac(codec, cfg->line_out_pins[i]);
17947 if (!dac)
17948 continue;
17949 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
17950 }
17951 return 0;
17952}
17953
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017954static inline int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020017955 hda_nid_t nid, unsigned int chs)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017956{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017957 return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020017958 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
17959}
17960
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017961static inline int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020017962 hda_nid_t nid, unsigned int chs)
17963{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017964 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020017965 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
17966}
17967
17968#define alc662_add_stereo_vol(spec, pfx, nid) \
17969 alc662_add_vol_ctl(spec, pfx, nid, 3)
17970#define alc662_add_stereo_sw(spec, pfx, nid) \
17971 alc662_add_sw_ctl(spec, pfx, nid, 3)
17972
17973/* add playback controls from the parsed DAC table */
17974static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
17975 const struct auto_pin_cfg *cfg)
17976{
17977 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017978 static const char *chname[4] = {
17979 "Front", "Surround", NULL /*CLFE*/, "Side"
17980 };
Takashi Iwai7085ec12009-10-02 09:03:58 +020017981 hda_nid_t nid, mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017982 int i, err;
17983
17984 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020017985 nid = spec->multiout.dac_nids[i];
17986 if (!nid)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017987 continue;
Takashi Iwai7085ec12009-10-02 09:03:58 +020017988 mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid);
17989 if (!mix)
17990 continue;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017991 if (i == 2) {
17992 /* Center/LFE */
Takashi Iwai7085ec12009-10-02 09:03:58 +020017993 err = alc662_add_vol_ctl(spec, "Center", nid, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017994 if (err < 0)
17995 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020017996 err = alc662_add_vol_ctl(spec, "LFE", nid, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017997 if (err < 0)
17998 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020017999 err = alc662_add_sw_ctl(spec, "Center", mix, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018000 if (err < 0)
18001 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018002 err = alc662_add_sw_ctl(spec, "LFE", mix, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018003 if (err < 0)
18004 return err;
18005 } else {
Takashi Iwai0d884cb2009-08-25 16:14:35 +020018006 const char *pfx;
18007 if (cfg->line_outs == 1 &&
18008 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020018009 if (cfg->hp_outs)
Takashi Iwai0d884cb2009-08-25 16:14:35 +020018010 pfx = "Speaker";
18011 else
18012 pfx = "PCM";
18013 } else
18014 pfx = chname[i];
Takashi Iwai7085ec12009-10-02 09:03:58 +020018015 err = alc662_add_vol_ctl(spec, pfx, nid, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018016 if (err < 0)
18017 return err;
Takashi Iwai0d884cb2009-08-25 16:14:35 +020018018 if (cfg->line_outs == 1 &&
18019 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
18020 pfx = "Speaker";
Takashi Iwai7085ec12009-10-02 09:03:58 +020018021 err = alc662_add_sw_ctl(spec, pfx, mix, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018022 if (err < 0)
18023 return err;
18024 }
18025 }
18026 return 0;
18027}
18028
18029/* add playback controls for speaker and HP outputs */
Takashi Iwai7085ec12009-10-02 09:03:58 +020018030/* return DAC nid if any new DAC is assigned */
18031static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018032 const char *pfx)
18033{
Takashi Iwai7085ec12009-10-02 09:03:58 +020018034 struct alc_spec *spec = codec->spec;
18035 hda_nid_t nid, mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018036 int err;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018037
18038 if (!pin)
18039 return 0;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018040 nid = alc662_look_for_dac(codec, pin);
18041 if (!nid) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020018042 /* the corresponding DAC is already occupied */
18043 if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
18044 return 0; /* no way */
18045 /* create a switch only */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018046 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018047 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
18048 }
18049
18050 mix = alc662_dac_to_mix(codec, pin, nid);
18051 if (!mix)
18052 return 0;
18053 err = alc662_add_vol_ctl(spec, pfx, nid, 3);
18054 if (err < 0)
Takashi Iwai24fb9172008-09-02 14:48:20 +020018055 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018056 err = alc662_add_sw_ctl(spec, pfx, mix, 3);
18057 if (err < 0)
18058 return err;
18059 return nid;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018060}
18061
18062/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020018063#define alc662_auto_create_input_ctls \
Takashi Iwai4b7348a2009-10-14 18:25:23 +020018064 alc882_auto_create_input_ctls
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018065
18066static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
18067 hda_nid_t nid, int pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018068 hda_nid_t dac)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018069{
Takashi Iwai7085ec12009-10-02 09:03:58 +020018070 int i, num;
18071 hda_nid_t srcs[4];
18072
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018073 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018074 /* need the manual connection? */
Takashi Iwai7085ec12009-10-02 09:03:58 +020018075 num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
18076 if (num <= 1)
18077 return;
18078 for (i = 0; i < num; i++) {
18079 if (alc662_mix_to_dac(srcs[i]) != dac)
18080 continue;
18081 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
18082 return;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018083 }
18084}
18085
18086static void alc662_auto_init_multi_out(struct hda_codec *codec)
18087{
18088 struct alc_spec *spec = codec->spec;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018089 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018090 int i;
18091
18092 for (i = 0; i <= HDA_SIDE; i++) {
18093 hda_nid_t nid = spec->autocfg.line_out_pins[i];
18094 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020018095 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018096 spec->multiout.dac_nids[i]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018097 }
18098}
18099
18100static void alc662_auto_init_hp_out(struct hda_codec *codec)
18101{
18102 struct alc_spec *spec = codec->spec;
18103 hda_nid_t pin;
18104
18105 pin = spec->autocfg.hp_pins[0];
Takashi Iwai7085ec12009-10-02 09:03:58 +020018106 if (pin)
18107 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP,
18108 spec->multiout.hp_nid);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018109 pin = spec->autocfg.speaker_pins[0];
18110 if (pin)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018111 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT,
18112 spec->multiout.extra_out_nid[0]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018113}
18114
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018115#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
18116
18117static void alc662_auto_init_analog_input(struct hda_codec *codec)
18118{
18119 struct alc_spec *spec = codec->spec;
18120 int i;
18121
18122 for (i = 0; i < AUTO_PIN_LAST; i++) {
18123 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai05f5f472009-08-25 13:10:18 +020018124 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +010018125 alc_set_input_pin(codec, nid, i);
Takashi Iwai52ca15b2009-03-23 12:51:55 +010018126 if (nid != ALC662_PIN_CD_NID &&
Takashi Iwaie82c0252009-03-23 15:17:38 +010018127 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018128 snd_hda_codec_write(codec, nid, 0,
18129 AC_VERB_SET_AMP_GAIN_MUTE,
18130 AMP_OUT_MUTE);
18131 }
18132 }
18133}
18134
Takashi Iwaif511b012008-08-15 16:46:42 +020018135#define alc662_auto_init_input_src alc882_auto_init_input_src
18136
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018137static int alc662_parse_auto_config(struct hda_codec *codec)
18138{
18139 struct alc_spec *spec = codec->spec;
18140 int err;
18141 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
18142
18143 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
18144 alc662_ignore);
18145 if (err < 0)
18146 return err;
18147 if (!spec->autocfg.line_outs)
18148 return 0; /* can't find valid BIOS pin config */
18149
Takashi Iwai7085ec12009-10-02 09:03:58 +020018150 err = alc662_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018151 if (err < 0)
18152 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018153 err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018154 if (err < 0)
18155 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018156 err = alc662_auto_create_extra_out(codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018157 spec->autocfg.speaker_pins[0],
18158 "Speaker");
18159 if (err < 0)
18160 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018161 if (err)
18162 spec->multiout.extra_out_nid[0] = err;
18163 err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018164 "Headphone");
18165 if (err < 0)
18166 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018167 if (err)
18168 spec->multiout.hp_nid = err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020018169 err = alc662_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018170 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018171 return err;
18172
18173 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
18174
Takashi Iwai0852d7a2009-02-11 11:35:15 +010018175 if (spec->autocfg.dig_outs)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018176 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
18177
Takashi Iwai603c4012008-07-30 15:01:44 +020018178 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010018179 add_mixer(spec, spec->kctls.list);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018180
18181 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020018182 spec->input_mux = &spec->private_imux[0];
Kailang Yangea1fb292008-08-26 12:58:38 +020018183
Kailang Yangcec27c82010-02-04 14:18:18 +010018184 add_verb(spec, alc662_init_verbs);
18185 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
18186 codec->vendor_id == 0x10ec0665)
18187 add_verb(spec, alc663_init_verbs);
18188
18189 if (codec->vendor_id == 0x10ec0272)
18190 add_verb(spec, alc272_init_verbs);
Takashi Iwaiee979a142008-09-02 15:42:20 +020018191
18192 err = alc_auto_add_mic_boost(codec);
18193 if (err < 0)
18194 return err;
18195
Takashi Iwai4a79ba32009-04-22 16:31:35 +020018196 alc_ssid_check(codec, 0x15, 0x1b, 0x14);
18197
Takashi Iwai8c872862007-06-19 12:11:16 +020018198 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018199}
18200
18201/* additional initialization for auto-configuration model */
18202static void alc662_auto_init(struct hda_codec *codec)
18203{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018204 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018205 alc662_auto_init_multi_out(codec);
18206 alc662_auto_init_hp_out(codec);
18207 alc662_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020018208 alc662_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018209 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020018210 alc_inithook(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018211}
18212
18213static int patch_alc662(struct hda_codec *codec)
18214{
18215 struct alc_spec *spec;
18216 int err, board_config;
18217
18218 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
18219 if (!spec)
18220 return -ENOMEM;
18221
18222 codec->spec = spec;
18223
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020018224 alc_fix_pll_init(codec, 0x20, 0x04, 15);
18225
Kailang Yang274693f2009-12-03 10:07:50 +010018226 if (alc_read_coef_idx(codec, 0)==0x8020){
18227 kfree(codec->chip_name);
18228 codec->chip_name = kstrdup("ALC661", GFP_KERNEL);
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010018229 if (!codec->chip_name) {
18230 alc_free(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010018231 return -ENOMEM;
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010018232 }
Kailang Yang274693f2009-12-03 10:07:50 +010018233 }
18234
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018235 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
18236 alc662_models,
18237 alc662_cfg_tbl);
18238 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020018239 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
18240 codec->chip_name);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018241 board_config = ALC662_AUTO;
18242 }
18243
18244 if (board_config == ALC662_AUTO) {
18245 /* automatic parse from the BIOS config */
18246 err = alc662_parse_auto_config(codec);
18247 if (err < 0) {
18248 alc_free(codec);
18249 return err;
Takashi Iwai8c872862007-06-19 12:11:16 +020018250 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018251 printk(KERN_INFO
18252 "hda_codec: Cannot set up configuration "
18253 "from BIOS. Using base mode...\n");
18254 board_config = ALC662_3ST_2ch_DIG;
18255 }
18256 }
18257
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090018258 err = snd_hda_attach_beep_device(codec, 0x1);
18259 if (err < 0) {
18260 alc_free(codec);
18261 return err;
18262 }
18263
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018264 if (board_config != ALC662_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020018265 setup_preset(codec, &alc662_presets[board_config]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018266
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018267 spec->stream_analog_playback = &alc662_pcm_analog_playback;
18268 spec->stream_analog_capture = &alc662_pcm_analog_capture;
18269
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018270 spec->stream_digital_playback = &alc662_pcm_digital_playback;
18271 spec->stream_digital_capture = &alc662_pcm_digital_capture;
18272
Takashi Iwaidd704692009-08-11 08:45:11 +020018273 if (!spec->adc_nids) {
18274 spec->adc_nids = alc662_adc_nids;
18275 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
18276 }
18277 if (!spec->capsrc_nids)
18278 spec->capsrc_nids = alc662_capsrc_nids;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018279
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018280 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020018281 set_capture_mixer(codec);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018282
Kailang Yangcec27c82010-02-04 14:18:18 +010018283 switch (codec->vendor_id) {
18284 case 0x10ec0662:
18285 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
18286 break;
18287 case 0x10ec0272:
18288 case 0x10ec0663:
18289 case 0x10ec0665:
18290 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
18291 break;
18292 case 0x10ec0273:
18293 set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
18294 break;
18295 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010018296 spec->vmaster_nid = 0x02;
18297
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018298 codec->patch_ops = alc_patch_ops;
18299 if (board_config == ALC662_AUTO)
18300 spec->init_hook = alc662_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020018301#ifdef CONFIG_SND_HDA_POWER_SAVE
18302 if (!spec->loopback.amplist)
18303 spec->loopback.amplist = alc662_loopbacks;
18304#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018305
18306 return 0;
18307}
18308
Kailang Yang274693f2009-12-03 10:07:50 +010018309static int patch_alc888(struct hda_codec *codec)
18310{
18311 if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){
18312 kfree(codec->chip_name);
18313 codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010018314 if (!codec->chip_name) {
18315 alc_free(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010018316 return -ENOMEM;
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010018317 }
18318 return patch_alc662(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010018319 }
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010018320 return patch_alc882(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010018321}
18322
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018323/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070018324 * patch entries
18325 */
Takashi Iwai1289e9e2008-11-27 15:47:11 +010018326static struct hda_codec_preset snd_hda_preset_realtek[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070018327 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010018328 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010018329 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020018330 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010018331 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010018332 { .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +020018333 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010018334 { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010018335 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018336 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010018337 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
18338 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
18339 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018340 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
Takashi Iwai4953550a2009-06-30 15:28:30 +020018341 .patch = patch_alc882 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018342 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
18343 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018344 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Kailang Yangcec27c82010-02-04 14:18:18 +010018345 { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010018346 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070018347 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020018348 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
Clive Messer669faba2008-09-30 15:49:13 +020018349 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
Takashi Iwai4953550a2009-06-30 15:28:30 +020018350 .patch = patch_alc882 },
Takashi Iwaicb308f92008-04-16 14:13:29 +020018351 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai4953550a2009-06-30 15:28:30 +020018352 .patch = patch_alc882 },
Kailang Yangdf694da2005-12-05 19:42:22 +010018353 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020018354 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 },
Kailang Yang44426082008-10-15 11:18:05 +020018355 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
Takashi Iwai4953550a2009-06-30 15:28:30 +020018356 .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010018357 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020018358 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010018359 { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070018360 {} /* terminator */
18361};
Takashi Iwai1289e9e2008-11-27 15:47:11 +010018362
18363MODULE_ALIAS("snd-hda-codec-id:10ec*");
18364
18365MODULE_LICENSE("GPL");
18366MODULE_DESCRIPTION("Realtek HD-audio codec");
18367
18368static struct hda_codec_preset_list realtek_list = {
18369 .preset = snd_hda_preset_realtek,
18370 .owner = THIS_MODULE,
18371};
18372
18373static int __init patch_realtek_init(void)
18374{
18375 return snd_hda_add_codec_preset(&realtek_list);
18376}
18377
18378static void __exit patch_realtek_exit(void)
18379{
18380 snd_hda_delete_codec_preset(&realtek_list);
18381}
18382
18383module_init(patch_realtek_init)
18384module_exit(patch_realtek_exit)