blob: 6b0b8728f6b77f3fa69be780836539b52a7b5c97 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for ALC 260/880/882 codecs
5 *
Kailang Yangdf694da2005-12-05 19:42:22 +01006 * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
7 * PeiSen Hou <pshou@realtek.com.tw>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * Takashi Iwai <tiwai@suse.de>
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01009 * Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * This driver is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This driver is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/init.h>
27#include <linux/delay.h>
28#include <linux/slab.h>
29#include <linux/pci.h>
30#include <sound/core.h>
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 Woithe7cf51e42006-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 Yangf53281e2008-07-18 12:36:43 +0200134 ALC269_ASUS_EEEPC_P703,
135 ALC269_ASUS_EEEPC_P901,
Takashi Iwai26f5df22008-11-03 17:39:46 +0100136 ALC269_FUJITSU,
Tony Vroon64154832008-11-06 15:08:49 +0000137 ALC269_LIFEBOOK,
Kailang Yangf6a92242007-12-13 16:52:54 +0100138 ALC269_AUTO,
139 ALC269_MODEL_LAST /* last tag */
140};
141
Kailang Yangdf694da2005-12-05 19:42:22 +0100142/* ALC861 models */
143enum {
144 ALC861_3ST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200145 ALC660_3ST,
Kailang Yangdf694da2005-12-05 19:42:22 +0100146 ALC861_3ST_DIG,
147 ALC861_6ST_DIG,
Takashi Iwai22309c32006-08-09 16:57:28 +0200148 ALC861_UNIWILL_M31,
Tobin Davisa53d1ae2006-10-17 12:00:28 +0200149 ALC861_TOSHIBA,
Mariusz Domanski7cdbff92006-10-23 13:42:56 +0200150 ALC861_ASUS,
Takashi Iwai56bb0ca2006-11-22 11:52:52 +0100151 ALC861_ASUS_LAPTOP,
Kailang Yangdf694da2005-12-05 19:42:22 +0100152 ALC861_AUTO,
153 ALC861_MODEL_LAST,
154};
155
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100156/* ALC861-VD models */
157enum {
158 ALC660VD_3ST,
Mike Crash6963f842007-06-25 12:12:51 +0200159 ALC660VD_3ST_DIG,
Takashi Iwai13c94742008-11-05 08:06:08 +0100160 ALC660VD_ASUS_V1S,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100161 ALC861VD_3ST,
162 ALC861VD_3ST_DIG,
163 ALC861VD_6ST_DIG,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200164 ALC861VD_LENOVO,
Kailang Yang272a5272007-05-14 11:00:38 +0200165 ALC861VD_DALLAS,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200166 ALC861VD_HP,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100167 ALC861VD_AUTO,
168 ALC861VD_MODEL_LAST,
169};
170
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200171/* ALC662 models */
172enum {
173 ALC662_3ST_2ch_DIG,
174 ALC662_3ST_6ch_DIG,
175 ALC662_3ST_6ch,
176 ALC662_5ST_DIG,
177 ALC662_LENOVO_101E,
Kailang Yang291702f2007-10-16 14:28:03 +0200178 ALC662_ASUS_EEEPC_P701,
Kailang Yang8c427222008-01-10 13:03:59 +0100179 ALC662_ASUS_EEEPC_EP20,
Kailang Yang6dda9f42008-05-27 12:05:31 +0200180 ALC663_ASUS_M51VA,
181 ALC663_ASUS_G71V,
182 ALC663_ASUS_H13,
183 ALC663_ASUS_G50V,
Kailang Yangf1d4e282008-08-26 14:03:29 +0200184 ALC662_ECS,
185 ALC663_ASUS_MODE1,
186 ALC662_ASUS_MODE2,
187 ALC663_ASUS_MODE3,
188 ALC663_ASUS_MODE4,
189 ALC663_ASUS_MODE5,
190 ALC663_ASUS_MODE6,
Kailang Yang622e84c2009-04-21 07:39:04 +0200191 ALC272_DELL,
192 ALC272_DELL_ZM1,
Chris Pockelé9541ba12009-05-12 08:08:53 +0200193 ALC272_SAMSUNG_NC10,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200194 ALC662_AUTO,
195 ALC662_MODEL_LAST,
196};
197
Kailang Yangdf694da2005-12-05 19:42:22 +0100198/* ALC882 models */
199enum {
200 ALC882_3ST_DIG,
201 ALC882_6ST_DIG,
Takashi Iwai4b146cb2006-07-28 14:42:36 +0200202 ALC882_ARIMA,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200203 ALC882_W2JC,
Kailang Yang272a5272007-05-14 11:00:38 +0200204 ALC882_TARGA,
205 ALC882_ASUS_A7J,
Takashi Iwai914759b2007-09-06 14:52:04 +0200206 ALC882_ASUS_A7M,
Tobin Davis9102cd12006-12-15 10:02:12 +0100207 ALC885_MACPRO,
Takashi Iwai87350ad2007-08-16 18:19:38 +0200208 ALC885_MBP3,
Kacper Szczesniak41d55452009-05-07 12:47:43 +0200209 ALC885_MB5,
Nicola Fagnanic54728d2007-07-19 23:28:52 +0200210 ALC885_IMAC24,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -0800211 ALC885_IMAC91,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200212 ALC883_3ST_2ch_DIG,
213 ALC883_3ST_6ch_DIG,
214 ALC883_3ST_6ch,
215 ALC883_6ST_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +0200216 ALC883_TARGA_DIG,
217 ALC883_TARGA_2ch_DIG,
David Heidelberger64a8be72009-06-08 16:15:18 +0200218 ALC883_TARGA_8ch_DIG,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +0200219 ALC883_ACER,
Tobin Davis2880a862007-08-07 11:50:26 +0200220 ALC883_ACER_ASPIRE,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +0800221 ALC888_ACER_ASPIRE_4930G,
Tony Vroond2fd4b02009-06-21 00:40:10 +0100222 ALC888_ACER_ASPIRE_6530G,
Hector Martin3b315d72009-06-02 10:54:19 +0200223 ALC888_ACER_ASPIRE_8930G,
Denis Kuplyakovfc86f952009-08-25 18:15:59 +0200224 ALC888_ACER_ASPIRE_7730G,
Tobin Davisc07584c2006-10-13 12:32:16 +0200225 ALC883_MEDION,
Kailang Yangea1fb292008-08-26 12:58:38 +0200226 ALC883_MEDION_MD2,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +0100227 ALC883_LAPTOP_EAPD,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200228 ALC883_LENOVO_101E_2ch,
Kailang Yang272a5272007-05-14 11:00:38 +0200229 ALC883_LENOVO_NB0763,
Kailang Yang189609a2007-08-20 11:31:23 +0200230 ALC888_LENOVO_MS7195_DIG,
Kailang Yange2757d52008-08-26 13:17:46 +0200231 ALC888_LENOVO_SKY,
Kailang Yangea1fb292008-08-26 12:58:38 +0200232 ALC883_HAIER_W66,
Claudio Matsuoka4723c022007-07-13 14:36:19 +0200233 ALC888_3ST_HP,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +0100234 ALC888_6ST_DELL,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +0100235 ALC883_MITAC,
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -0430236 ALC883_CLEVO_M540R,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +0100237 ALC883_CLEVO_M720,
Jiang zhefb97dc62008-03-06 11:07:11 +0100238 ALC883_FUJITSU_PI2515,
Vincent Petryef8ef5f2008-11-23 11:31:41 +0800239 ALC888_FUJITSU_XA3530,
Jiang zhe17bba1b2008-06-04 12:11:07 +0200240 ALC883_3ST_6ch_INTEL,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +0200241 ALC889A_INTEL,
242 ALC889_INTEL,
Kailang Yange2757d52008-08-26 13:17:46 +0200243 ALC888_ASUS_M90V,
244 ALC888_ASUS_EEE1601,
Torben Schulzeb4c41d2009-05-18 15:02:35 +0200245 ALC889A_MB31,
Wu Fengguang3ab90932008-11-17 09:51:09 +0100246 ALC1200_ASUS_P5Q,
Guido Günther3e1647c2009-06-05 00:47:26 +0200247 ALC883_SONY_VAIO_TT,
Takashi Iwai49535502009-06-30 15:28:30 +0200248 ALC882_AUTO,
249 ALC882_MODEL_LAST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200250};
251
Kailang Yangdf694da2005-12-05 19:42:22 +0100252/* for GPIO Poll */
253#define GPIO_MASK 0x03
254
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200255/* extra amp-initialization sequence types */
256enum {
257 ALC_INIT_NONE,
258 ALC_INIT_DEFAULT,
259 ALC_INIT_GPIO1,
260 ALC_INIT_GPIO2,
261 ALC_INIT_GPIO3,
262};
263
Takashi Iwai6c819492009-08-10 18:47:44 +0200264struct alc_mic_route {
265 hda_nid_t pin;
266 unsigned char mux_idx;
267 unsigned char amix_idx;
268};
269
270#define MUX_IDX_UNDEF ((unsigned char)-1)
271
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272struct alc_spec {
273 /* codec parameterization */
Kailang Yangdf694da2005-12-05 19:42:22 +0100274 struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 unsigned int num_mixers;
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100276 struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Takashi Iwai45bdd1c2009-02-06 16:11:25 +0100277 unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
Takashi Iwai2d9c6482009-10-13 08:06:55 +0200279 const struct hda_verb *init_verbs[10]; /* initialization verbs
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200280 * don't forget NULL
281 * termination!
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200282 */
283 unsigned int num_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
Takashi Iwaiaa563af2009-07-31 10:05:11 +0200285 char stream_name_analog[32]; /* analog PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 struct hda_pcm_stream *stream_analog_playback;
287 struct hda_pcm_stream *stream_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +0100288 struct hda_pcm_stream *stream_analog_alt_playback;
289 struct hda_pcm_stream *stream_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
Takashi Iwaiaa563af2009-07-31 10:05:11 +0200291 char stream_name_digital[32]; /* digital PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 struct hda_pcm_stream *stream_digital_playback;
293 struct hda_pcm_stream *stream_digital_capture;
294
295 /* playback */
Takashi Iwai16ded522005-06-10 19:58:24 +0200296 struct hda_multi_out multiout; /* playback set-up
297 * max_channels, dacs must be set
298 * dig_out_nid and hp_nid are optional
299 */
Takashi Iwai63300792008-01-24 15:31:36 +0100300 hda_nid_t alt_dac_nid;
Takashi Iwai6a05ac42009-02-13 11:19:09 +0100301 hda_nid_t slave_dig_outs[3]; /* optional - for auto-parsing */
Takashi Iwai8c441982009-01-20 18:30:20 +0100302 int dig_out_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
304 /* capture */
305 unsigned int num_adc_nids;
306 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100307 hda_nid_t *capsrc_nids;
Takashi Iwai16ded522005-06-10 19:58:24 +0200308 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
310 /* capture source */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200311 unsigned int num_mux_defs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 const struct hda_input_mux *input_mux;
313 unsigned int cur_mux[3];
Takashi Iwai6c819492009-08-10 18:47:44 +0200314 struct alc_mic_route ext_mic;
315 struct alc_mic_route int_mic;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
317 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100318 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 int num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200320 int need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200321 int const_channel_count;
322 int ext_channel_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
324 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100325 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200326
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200327 /* dynamic controls, init_verbs and input_mux */
328 struct auto_pin_cfg autocfg;
Takashi Iwai603c4012008-07-30 15:01:44 +0200329 struct snd_array kctls;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200330 struct hda_input_mux private_imux[3];
Takashi Iwai41923e42007-10-22 17:20:10 +0200331 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai49535502009-06-30 15:28:30 +0200332 hda_nid_t private_adc_nids[AUTO_CFG_MAX_OUTS];
333 hda_nid_t private_capsrc_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai834be882006-03-01 14:16:17 +0100334
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100335 /* hooks */
336 void (*init_hook)(struct hda_codec *codec);
337 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
338
Takashi Iwai834be882006-03-01 14:16:17 +0100339 /* for pin sensing */
340 unsigned int sense_updated: 1;
341 unsigned int jack_present: 1;
Takashi Iwaibec15c32008-01-28 18:16:30 +0100342 unsigned int master_sw: 1;
Takashi Iwai6c819492009-08-10 18:47:44 +0200343 unsigned int auto_mic:1;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200344
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100345 /* other flags */
346 unsigned int no_analog :1; /* digital I/O only */
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200347 int init_amp;
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100348
Takashi Iwai2134ea42008-01-10 16:53:55 +0100349 /* for virtual master */
350 hda_nid_t vmaster_nid;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200351#ifdef CONFIG_SND_HDA_POWER_SAVE
352 struct hda_loopback_check loopback;
353#endif
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200354
355 /* for PLL fix */
356 hda_nid_t pll_nid;
357 unsigned int pll_coef_idx, pll_coef_bit;
Kailang Yangdf694da2005-12-05 19:42:22 +0100358};
359
360/*
361 * configuration template - to be copied to the spec instance
362 */
363struct alc_config_preset {
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200364 struct snd_kcontrol_new *mixers[5]; /* should be identical size
365 * with spec
366 */
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100367 struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Kailang Yangdf694da2005-12-05 19:42:22 +0100368 const struct hda_verb *init_verbs[5];
369 unsigned int num_dacs;
370 hda_nid_t *dac_nids;
371 hda_nid_t dig_out_nid; /* optional */
372 hda_nid_t hp_nid; /* optional */
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800373 hda_nid_t *slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100374 unsigned int num_adc_nids;
375 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100376 hda_nid_t *capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100377 hda_nid_t dig_in_nid;
378 unsigned int num_channel_mode;
379 const struct hda_channel_mode *channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200380 int need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200381 int const_channel_count;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200382 unsigned int num_mux_defs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100383 const struct hda_input_mux *input_mux;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100384 void (*unsol_event)(struct hda_codec *, unsigned int);
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200385 void (*setup)(struct hda_codec *);
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100386 void (*init_hook)(struct hda_codec *);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200387#ifdef CONFIG_SND_HDA_POWER_SAVE
388 struct hda_amp_list *loopbacks;
389#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390};
391
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392
393/*
394 * input MUX handling
395 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200396static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
397 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398{
399 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
400 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200401 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
402 if (mux_idx >= spec->num_mux_defs)
403 mux_idx = 0;
404 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405}
406
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200407static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
408 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409{
410 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
411 struct alc_spec *spec = codec->spec;
412 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
413
414 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
415 return 0;
416}
417
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200418static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
419 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420{
421 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
422 struct alc_spec *spec = codec->spec;
Takashi Iwaicd896c32008-11-18 12:36:33 +0100423 const struct hda_input_mux *imux;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwaicd896c32008-11-18 12:36:33 +0100425 unsigned int mux_idx;
Takashi Iwaie1406342008-02-11 18:32:32 +0100426 hda_nid_t nid = spec->capsrc_nids ?
427 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Takashi Iwai0169b6b2009-06-22 10:50:19 +0200428 unsigned int type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429
Takashi Iwaicd896c32008-11-18 12:36:33 +0100430 mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
431 imux = &spec->input_mux[mux_idx];
432
Takashi Iwaia22d5432009-07-27 12:54:26 +0200433 type = get_wcaps_type(get_wcaps(codec, nid));
Takashi Iwai0169b6b2009-06-22 10:50:19 +0200434 if (type == AC_WID_AUD_MIX) {
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100435 /* Matrix-mixer style (e.g. ALC882) */
436 unsigned int *cur_val = &spec->cur_mux[adc_idx];
437 unsigned int i, idx;
438
439 idx = ucontrol->value.enumerated.item[0];
440 if (idx >= imux->num_items)
441 idx = imux->num_items - 1;
442 if (*cur_val == idx)
443 return 0;
444 for (i = 0; i < imux->num_items; i++) {
445 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
446 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
447 imux->items[i].index,
448 HDA_AMP_MUTE, v);
449 }
450 *cur_val = idx;
451 return 1;
452 } else {
453 /* MUX style (e.g. ALC880) */
Takashi Iwaicd896c32008-11-18 12:36:33 +0100454 return snd_hda_input_mux_put(codec, imux, ucontrol, nid,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100455 &spec->cur_mux[adc_idx]);
456 }
457}
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200458
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459/*
460 * channel mode setting
461 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200462static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
463 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464{
465 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
466 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100467 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
468 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469}
470
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200471static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
472 struct snd_ctl_elem_value *ucontrol)
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_get(codec, ucontrol, spec->channel_mode,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200477 spec->num_channel_mode,
Hector Martin3b315d72009-06-02 10:54:19 +0200478 spec->ext_channel_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479}
480
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200481static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
482 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483{
484 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
485 struct alc_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200486 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
487 spec->num_channel_mode,
Hector Martin3b315d72009-06-02 10:54:19 +0200488 &spec->ext_channel_count);
489 if (err >= 0 && !spec->const_channel_count) {
490 spec->multiout.max_channels = spec->ext_channel_count;
491 if (spec->need_dac_fix)
492 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
493 }
Takashi Iwai4e195a72006-07-28 14:47:34 +0200494 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495}
496
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100498 * Control the mode of pin widget settings via the mixer. "pc" is used
Kailang Yangea1fb292008-08-26 12:58:38 +0200499 * instead of "%" to avoid consequences of accidently treating the % as
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100500 * being part of a format specifier. Maximum allowed length of a value is
501 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100502 *
503 * Note: some retasking pin complexes seem to ignore requests for input
504 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
505 * are requested. Therefore order this list so that this behaviour will not
506 * cause problems when mixer clients move through the enum sequentially.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200507 * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
508 * March 2006.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200509 */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100510static char *alc_pin_mode_names[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100511 "Mic 50pc bias", "Mic 80pc bias",
512 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100513};
514static unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100515 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100516};
517/* The control can present all 5 options, or it can limit the options based
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200518 * in the pin being assumed to be exclusively an input or an output pin. In
519 * addition, "input" pins may or may not process the mic bias option
520 * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
521 * accept requests for bias as of chip versions up to March 2006) and/or
522 * wiring in the computer.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100523 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200524#define ALC_PIN_DIR_IN 0x00
525#define ALC_PIN_DIR_OUT 0x01
526#define ALC_PIN_DIR_INOUT 0x02
527#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
528#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100529
Kailang Yangea1fb292008-08-26 12:58:38 +0200530/* Info about the pin modes supported by the different pin direction modes.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100531 * For each direction the minimum and maximum values are given.
532 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200533static signed char alc_pin_mode_dir_info[5][2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100534 { 0, 2 }, /* ALC_PIN_DIR_IN */
535 { 3, 4 }, /* ALC_PIN_DIR_OUT */
536 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200537 { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
538 { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100539};
540#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
541#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
542#define alc_pin_mode_n_items(_dir) \
543 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
544
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200545static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
546 struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200547{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100548 unsigned int item_num = uinfo->value.enumerated.item;
549 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
550
551 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200552 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100553 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
554
555 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
556 item_num = alc_pin_mode_min(dir);
557 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200558 return 0;
559}
560
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200561static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
562 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200563{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100564 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200565 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
566 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100567 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200568 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200569 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
570 AC_VERB_GET_PIN_WIDGET_CONTROL,
571 0x00);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200572
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100573 /* Find enumerated value for current pinctl setting */
574 i = alc_pin_mode_min(dir);
Roel Kluin4b35d2c2009-08-02 13:30:45 +0200575 while (i <= alc_pin_mode_max(dir) && alc_pin_mode_values[i] != pinctl)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100576 i++;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200577 *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100578 return 0;
579}
580
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200581static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
582 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100583{
584 signed int change;
585 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
586 hda_nid_t nid = kcontrol->private_value & 0xffff;
587 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
588 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200589 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
590 AC_VERB_GET_PIN_WIDGET_CONTROL,
591 0x00);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100592
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200593 if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100594 val = alc_pin_mode_min(dir);
595
596 change = pinctl != alc_pin_mode_values[val];
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100597 if (change) {
598 /* Set pin mode to that requested */
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200599 snd_hda_codec_write_cache(codec, nid, 0,
600 AC_VERB_SET_PIN_WIDGET_CONTROL,
601 alc_pin_mode_values[val]);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100602
Kailang Yangea1fb292008-08-26 12:58:38 +0200603 /* Also enable the retasking pin's input/output as required
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100604 * for the requested pin mode. Enum values of 2 or less are
605 * input modes.
606 *
607 * Dynamically switching the input/output buffers probably
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200608 * reduces noise slightly (particularly on input) so we'll
609 * do it. However, having both input and output buffers
610 * enabled simultaneously doesn't seem to be problematic if
611 * this turns out to be necessary in the future.
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100612 */
613 if (val <= 2) {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200614 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
615 HDA_AMP_MUTE, HDA_AMP_MUTE);
616 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
617 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100618 } else {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200619 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
620 HDA_AMP_MUTE, HDA_AMP_MUTE);
621 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
622 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100623 }
624 }
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200625 return change;
626}
627
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100628#define ALC_PIN_MODE(xname, nid, dir) \
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200629 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100630 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100631 .info = alc_pin_mode_info, \
632 .get = alc_pin_mode_get, \
633 .put = alc_pin_mode_put, \
634 .private_value = nid | (dir<<16) }
Kailang Yangdf694da2005-12-05 19:42:22 +0100635
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100636/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
637 * together using a mask with more than one bit set. This control is
638 * currently used only by the ALC260 test model. At this stage they are not
639 * needed for any "production" models.
640 */
641#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200642#define alc_gpio_data_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200643
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200644static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
645 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100646{
647 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
648 hda_nid_t nid = kcontrol->private_value & 0xffff;
649 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
650 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200651 unsigned int val = snd_hda_codec_read(codec, nid, 0,
652 AC_VERB_GET_GPIO_DATA, 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100653
654 *valp = (val & mask) != 0;
655 return 0;
656}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200657static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
658 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100659{
660 signed int change;
661 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
662 hda_nid_t nid = kcontrol->private_value & 0xffff;
663 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
664 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200665 unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
666 AC_VERB_GET_GPIO_DATA,
667 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100668
669 /* Set/unset the masked GPIO bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200670 change = (val == 0 ? 0 : mask) != (gpio_data & mask);
671 if (val == 0)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100672 gpio_data &= ~mask;
673 else
674 gpio_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200675 snd_hda_codec_write_cache(codec, nid, 0,
676 AC_VERB_SET_GPIO_DATA, gpio_data);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100677
678 return change;
679}
680#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
681 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100682 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100683 .info = alc_gpio_data_info, \
684 .get = alc_gpio_data_get, \
685 .put = alc_gpio_data_put, \
686 .private_value = nid | (mask<<16) }
687#endif /* CONFIG_SND_DEBUG */
688
Jonathan Woithe92621f12006-02-28 11:47:47 +0100689/* A switch control to allow the enabling of the digital IO pins on the
690 * ALC260. This is incredibly simplistic; the intention of this control is
691 * to provide something in the test model allowing digital outputs to be
692 * identified if present. If models are found which can utilise these
693 * outputs a more complete mixer control can be devised for those models if
694 * necessary.
695 */
696#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200697#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200698
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200699static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
700 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100701{
702 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
703 hda_nid_t nid = kcontrol->private_value & 0xffff;
704 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
705 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200706 unsigned int val = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100707 AC_VERB_GET_DIGI_CONVERT_1, 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100708
709 *valp = (val & mask) != 0;
710 return 0;
711}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200712static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
713 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100714{
715 signed int change;
716 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
717 hda_nid_t nid = kcontrol->private_value & 0xffff;
718 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
719 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200720 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100721 AC_VERB_GET_DIGI_CONVERT_1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200722 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100723
724 /* Set/unset the masked control bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200725 change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100726 if (val==0)
727 ctrl_data &= ~mask;
728 else
729 ctrl_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200730 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
731 ctrl_data);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100732
733 return change;
734}
735#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
736 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100737 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe92621f12006-02-28 11:47:47 +0100738 .info = alc_spdif_ctrl_info, \
739 .get = alc_spdif_ctrl_get, \
740 .put = alc_spdif_ctrl_put, \
741 .private_value = nid | (mask<<16) }
742#endif /* CONFIG_SND_DEBUG */
743
Jonathan Woithef8225f62008-01-08 12:16:54 +0100744/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
745 * Again, this is only used in the ALC26x test models to help identify when
746 * the EAPD line must be asserted for features to work.
747 */
748#ifdef CONFIG_SND_DEBUG
749#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
750
751static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
752 struct snd_ctl_elem_value *ucontrol)
753{
754 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
755 hda_nid_t nid = kcontrol->private_value & 0xffff;
756 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
757 long *valp = ucontrol->value.integer.value;
758 unsigned int val = snd_hda_codec_read(codec, nid, 0,
759 AC_VERB_GET_EAPD_BTLENABLE, 0x00);
760
761 *valp = (val & mask) != 0;
762 return 0;
763}
764
765static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
766 struct snd_ctl_elem_value *ucontrol)
767{
768 int change;
769 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
770 hda_nid_t nid = kcontrol->private_value & 0xffff;
771 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
772 long val = *ucontrol->value.integer.value;
773 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
774 AC_VERB_GET_EAPD_BTLENABLE,
775 0x00);
776
777 /* Set/unset the masked control bit(s) as needed */
778 change = (!val ? 0 : mask) != (ctrl_data & mask);
779 if (!val)
780 ctrl_data &= ~mask;
781 else
782 ctrl_data |= mask;
783 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
784 ctrl_data);
785
786 return change;
787}
788
789#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
790 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100791 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithef8225f62008-01-08 12:16:54 +0100792 .info = alc_eapd_ctrl_info, \
793 .get = alc_eapd_ctrl_get, \
794 .put = alc_eapd_ctrl_put, \
795 .private_value = nid | (mask<<16) }
796#endif /* CONFIG_SND_DEBUG */
797
Kailang Yangdf694da2005-12-05 19:42:22 +0100798/*
Takashi Iwai23f0c042009-02-26 13:03:58 +0100799 * set up the input pin config (depending on the given auto-pin type)
800 */
801static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
802 int auto_pin_type)
803{
804 unsigned int val = PIN_IN;
805
806 if (auto_pin_type <= AUTO_PIN_FRONT_MIC) {
807 unsigned int pincap;
Takashi Iwai1327a322009-03-23 13:07:47 +0100808 pincap = snd_hda_query_pin_caps(codec, nid);
Takashi Iwai23f0c042009-02-26 13:03:58 +0100809 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
810 if (pincap & AC_PINCAP_VREF_80)
811 val = PIN_VREF80;
Takashi Iwai461c6c32009-05-25 08:06:02 +0200812 else if (pincap & AC_PINCAP_VREF_50)
813 val = PIN_VREF50;
814 else if (pincap & AC_PINCAP_VREF_100)
815 val = PIN_VREF100;
816 else if (pincap & AC_PINCAP_VREF_GRD)
817 val = PIN_VREFGRD;
Takashi Iwai23f0c042009-02-26 13:03:58 +0100818 }
819 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
820}
821
822/*
Takashi Iwaid88897e2008-10-31 15:01:37 +0100823 */
824static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix)
825{
826 if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
827 return;
828 spec->mixers[spec->num_mixers++] = mix;
829}
830
831static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
832{
833 if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
834 return;
835 spec->init_verbs[spec->num_init_verbs++] = verb;
836}
837
Takashi Iwaidaead532008-11-28 12:55:36 +0100838#ifdef CONFIG_PROC_FS
839/*
840 * hook for proc
841 */
842static void print_realtek_coef(struct snd_info_buffer *buffer,
843 struct hda_codec *codec, hda_nid_t nid)
844{
845 int coeff;
846
847 if (nid != 0x20)
848 return;
849 coeff = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0);
850 snd_iprintf(buffer, " Processing Coefficient: 0x%02x\n", coeff);
851 coeff = snd_hda_codec_read(codec, nid, 0,
852 AC_VERB_GET_COEF_INDEX, 0);
853 snd_iprintf(buffer, " Coefficient Index: 0x%02x\n", coeff);
854}
855#else
856#define print_realtek_coef NULL
857#endif
858
Takashi Iwaid88897e2008-10-31 15:01:37 +0100859/*
Kailang Yangdf694da2005-12-05 19:42:22 +0100860 * set up from the preset table
861 */
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200862static void setup_preset(struct hda_codec *codec,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200863 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100864{
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200865 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +0100866 int i;
867
868 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100869 add_mixer(spec, preset->mixers[i]);
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100870 spec->cap_mixer = preset->cap_mixer;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200871 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
872 i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100873 add_verb(spec, preset->init_verbs[i]);
Kailang Yangea1fb292008-08-26 12:58:38 +0200874
Kailang Yangdf694da2005-12-05 19:42:22 +0100875 spec->channel_mode = preset->channel_mode;
876 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200877 spec->need_dac_fix = preset->need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200878 spec->const_channel_count = preset->const_channel_count;
Kailang Yangdf694da2005-12-05 19:42:22 +0100879
Hector Martin3b315d72009-06-02 10:54:19 +0200880 if (preset->const_channel_count)
881 spec->multiout.max_channels = preset->const_channel_count;
882 else
883 spec->multiout.max_channels = spec->channel_mode[0].channels;
884 spec->ext_channel_count = spec->channel_mode[0].channels;
Kailang Yangdf694da2005-12-05 19:42:22 +0100885
886 spec->multiout.num_dacs = preset->num_dacs;
887 spec->multiout.dac_nids = preset->dac_nids;
888 spec->multiout.dig_out_nid = preset->dig_out_nid;
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800889 spec->multiout.slave_dig_outs = preset->slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100890 spec->multiout.hp_nid = preset->hp_nid;
Kailang Yangea1fb292008-08-26 12:58:38 +0200891
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200892 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200893 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200894 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100895 spec->input_mux = preset->input_mux;
896
897 spec->num_adc_nids = preset->num_adc_nids;
898 spec->adc_nids = preset->adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100899 spec->capsrc_nids = preset->capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100900 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100901
902 spec->unsol_event = preset->unsol_event;
903 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200904#ifdef CONFIG_SND_HDA_POWER_SAVE
905 spec->loopback.amplist = preset->loopbacks;
906#endif
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200907
908 if (preset->setup)
909 preset->setup(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +0100910}
911
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200912/* Enable GPIO mask and set output */
913static struct hda_verb alc_gpio1_init_verbs[] = {
914 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
915 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
916 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
917 { }
918};
919
920static struct hda_verb alc_gpio2_init_verbs[] = {
921 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
922 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
923 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
924 { }
925};
926
Kailang Yangbdd148a2007-05-08 15:19:08 +0200927static struct hda_verb alc_gpio3_init_verbs[] = {
928 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
929 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
930 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
931 { }
932};
933
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200934/*
935 * Fix hardware PLL issue
936 * On some codecs, the analog PLL gating control must be off while
937 * the default value is 1.
938 */
939static void alc_fix_pll(struct hda_codec *codec)
940{
941 struct alc_spec *spec = codec->spec;
942 unsigned int val;
943
944 if (!spec->pll_nid)
945 return;
946 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
947 spec->pll_coef_idx);
948 val = snd_hda_codec_read(codec, spec->pll_nid, 0,
949 AC_VERB_GET_PROC_COEF, 0);
950 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
951 spec->pll_coef_idx);
952 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
953 val & ~(1 << spec->pll_coef_bit));
954}
955
956static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
957 unsigned int coef_idx, unsigned int coef_bit)
958{
959 struct alc_spec *spec = codec->spec;
960 spec->pll_nid = nid;
961 spec->pll_coef_idx = coef_idx;
962 spec->pll_coef_bit = coef_bit;
963 alc_fix_pll(codec);
964}
965
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200966static void alc_automute_pin(struct hda_codec *codec)
Kailang Yangc9b58002007-10-16 14:30:01 +0200967{
968 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200969 unsigned int nid = spec->autocfg.hp_pins[0];
970 int i;
Kailang Yangc9b58002007-10-16 14:30:01 +0200971
Takashi Iwaiad87c642009-11-02 14:23:15 +0100972 if (!nid)
973 return;
Wu Fengguang864f92b2009-11-18 12:38:02 +0800974 spec->jack_present = snd_hda_jack_detect(codec, nid);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200975 for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
976 nid = spec->autocfg.speaker_pins[i];
977 if (!nid)
978 break;
979 snd_hda_codec_write(codec, nid, 0,
980 AC_VERB_SET_PIN_WIDGET_CONTROL,
981 spec->jack_present ? 0 : PIN_OUT);
982 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200983}
984
Takashi Iwai6c819492009-08-10 18:47:44 +0200985static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
986 hda_nid_t nid)
987{
988 hda_nid_t conn[HDA_MAX_NUM_INPUTS];
989 int i, nums;
990
991 nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
992 for (i = 0; i < nums; i++)
993 if (conn[i] == nid)
994 return i;
995 return -1;
996}
997
Kailang Yang7fb0d782008-10-15 11:12:35 +0200998static void alc_mic_automute(struct hda_codec *codec)
999{
1000 struct alc_spec *spec = codec->spec;
Takashi Iwai6c819492009-08-10 18:47:44 +02001001 struct alc_mic_route *dead, *alive;
1002 unsigned int present, type;
1003 hda_nid_t cap_nid;
Kailang Yang7fb0d782008-10-15 11:12:35 +02001004
Takashi Iwaib59bdf32009-08-11 09:47:30 +02001005 if (!spec->auto_mic)
1006 return;
Takashi Iwai6c819492009-08-10 18:47:44 +02001007 if (!spec->int_mic.pin || !spec->ext_mic.pin)
1008 return;
1009 if (snd_BUG_ON(!spec->adc_nids))
1010 return;
1011
1012 cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0];
1013
Wu Fengguang864f92b2009-11-18 12:38:02 +08001014 present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
Takashi Iwai6c819492009-08-10 18:47:44 +02001015 if (present) {
1016 alive = &spec->ext_mic;
1017 dead = &spec->int_mic;
1018 } else {
1019 alive = &spec->int_mic;
1020 dead = &spec->ext_mic;
1021 }
1022
Takashi Iwai6c819492009-08-10 18:47:44 +02001023 type = get_wcaps_type(get_wcaps(codec, cap_nid));
1024 if (type == AC_WID_AUD_MIX) {
1025 /* Matrix-mixer style (e.g. ALC882) */
1026 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1027 alive->mux_idx,
1028 HDA_AMP_MUTE, 0);
1029 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1030 dead->mux_idx,
1031 HDA_AMP_MUTE, HDA_AMP_MUTE);
1032 } else {
1033 /* MUX style (e.g. ALC880) */
1034 snd_hda_codec_write_cache(codec, cap_nid, 0,
1035 AC_VERB_SET_CONNECT_SEL,
1036 alive->mux_idx);
1037 }
1038
1039 /* FIXME: analog mixer */
Kailang Yang7fb0d782008-10-15 11:12:35 +02001040}
1041
Kailang Yangc9b58002007-10-16 14:30:01 +02001042/* unsolicited event for HP jack sensing */
1043static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
1044{
1045 if (codec->vendor_id == 0x10ec0880)
1046 res >>= 28;
1047 else
1048 res >>= 26;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001049 switch (res) {
1050 case ALC880_HP_EVENT:
1051 alc_automute_pin(codec);
1052 break;
1053 case ALC880_MIC_EVENT:
Kailang Yang7fb0d782008-10-15 11:12:35 +02001054 alc_mic_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001055 break;
1056 }
Kailang Yang7fb0d782008-10-15 11:12:35 +02001057}
1058
1059static void alc_inithook(struct hda_codec *codec)
1060{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001061 alc_automute_pin(codec);
Kailang Yang7fb0d782008-10-15 11:12:35 +02001062 alc_mic_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +02001063}
1064
Kailang Yangf9423e72008-05-27 12:32:25 +02001065/* additional initialization for ALC888 variants */
1066static void alc888_coef_init(struct hda_codec *codec)
1067{
1068 unsigned int tmp;
1069
1070 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
1071 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
1072 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
Takashi Iwai37db6232009-03-05 09:40:16 +01001073 if ((tmp & 0xf0) == 0x20)
Kailang Yangf9423e72008-05-27 12:32:25 +02001074 /* alc888S-VC */
1075 snd_hda_codec_read(codec, 0x20, 0,
1076 AC_VERB_SET_PROC_COEF, 0x830);
1077 else
1078 /* alc888-VB */
1079 snd_hda_codec_read(codec, 0x20, 0,
1080 AC_VERB_SET_PROC_COEF, 0x3030);
1081}
1082
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02001083static void alc889_coef_init(struct hda_codec *codec)
1084{
1085 unsigned int tmp;
1086
1087 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
1088 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
1089 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
1090 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, tmp|0x2010);
1091}
1092
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001093static void alc_auto_init_amp(struct hda_codec *codec, int type)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001094{
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001095 unsigned int tmp;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001096
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001097 switch (type) {
1098 case ALC_INIT_GPIO1:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001099 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
1100 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001101 case ALC_INIT_GPIO2:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001102 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
1103 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001104 case ALC_INIT_GPIO3:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001105 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
1106 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001107 case ALC_INIT_DEFAULT:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001108 switch (codec->vendor_id) {
Kailang Yangc9b58002007-10-16 14:30:01 +02001109 case 0x10ec0260:
1110 snd_hda_codec_write(codec, 0x0f, 0,
1111 AC_VERB_SET_EAPD_BTLENABLE, 2);
1112 snd_hda_codec_write(codec, 0x10, 0,
1113 AC_VERB_SET_EAPD_BTLENABLE, 2);
1114 break;
1115 case 0x10ec0262:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001116 case 0x10ec0267:
1117 case 0x10ec0268:
Kailang Yangc9b58002007-10-16 14:30:01 +02001118 case 0x10ec0269:
Takashi Iwaic6e8f2d2009-02-06 12:45:52 +01001119 case 0x10ec0272:
Kailang Yangf9423e72008-05-27 12:32:25 +02001120 case 0x10ec0660:
1121 case 0x10ec0662:
1122 case 0x10ec0663:
Kailang Yangc9b58002007-10-16 14:30:01 +02001123 case 0x10ec0862:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001124 case 0x10ec0889:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001125 snd_hda_codec_write(codec, 0x14, 0,
1126 AC_VERB_SET_EAPD_BTLENABLE, 2);
1127 snd_hda_codec_write(codec, 0x15, 0,
1128 AC_VERB_SET_EAPD_BTLENABLE, 2);
Kailang Yangc9b58002007-10-16 14:30:01 +02001129 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +02001130 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001131 switch (codec->vendor_id) {
1132 case 0x10ec0260:
1133 snd_hda_codec_write(codec, 0x1a, 0,
1134 AC_VERB_SET_COEF_INDEX, 7);
1135 tmp = snd_hda_codec_read(codec, 0x1a, 0,
1136 AC_VERB_GET_PROC_COEF, 0);
1137 snd_hda_codec_write(codec, 0x1a, 0,
1138 AC_VERB_SET_COEF_INDEX, 7);
1139 snd_hda_codec_write(codec, 0x1a, 0,
1140 AC_VERB_SET_PROC_COEF,
1141 tmp | 0x2010);
1142 break;
1143 case 0x10ec0262:
1144 case 0x10ec0880:
1145 case 0x10ec0882:
1146 case 0x10ec0883:
1147 case 0x10ec0885:
Takashi Iwai4a5a4c52009-02-06 12:46:59 +01001148 case 0x10ec0887:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001149 case 0x10ec0889:
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02001150 alc889_coef_init(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +02001151 break;
Kailang Yangf9423e72008-05-27 12:32:25 +02001152 case 0x10ec0888:
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001153 alc888_coef_init(codec);
Kailang Yangf9423e72008-05-27 12:32:25 +02001154 break;
Kailang Yangc9b58002007-10-16 14:30:01 +02001155 case 0x10ec0267:
1156 case 0x10ec0268:
1157 snd_hda_codec_write(codec, 0x20, 0,
1158 AC_VERB_SET_COEF_INDEX, 7);
1159 tmp = snd_hda_codec_read(codec, 0x20, 0,
1160 AC_VERB_GET_PROC_COEF, 0);
1161 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001162 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001163 snd_hda_codec_write(codec, 0x20, 0,
1164 AC_VERB_SET_PROC_COEF,
1165 tmp | 0x3000);
1166 break;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001167 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001168 break;
1169 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001170}
Kailang Yangea1fb292008-08-26 12:58:38 +02001171
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001172static void alc_init_auto_hp(struct hda_codec *codec)
1173{
1174 struct alc_spec *spec = codec->spec;
1175
1176 if (!spec->autocfg.hp_pins[0])
Kailang Yangc9b58002007-10-16 14:30:01 +02001177 return;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001178
Kailang Yangc9b58002007-10-16 14:30:01 +02001179 if (!spec->autocfg.speaker_pins[0]) {
Takashi Iwai2a2ed0d2009-04-28 13:01:26 +02001180 if (spec->autocfg.line_out_pins[0] &&
1181 spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
Kailang Yangc9b58002007-10-16 14:30:01 +02001182 spec->autocfg.speaker_pins[0] =
Kailang Yang8c427222008-01-10 13:03:59 +01001183 spec->autocfg.line_out_pins[0];
Kailang Yangc9b58002007-10-16 14:30:01 +02001184 else
1185 return;
1186 }
1187
Takashi Iwai2a2ed0d2009-04-28 13:01:26 +02001188 snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
1189 spec->autocfg.hp_pins[0]);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001190 snd_hda_codec_write_cache(codec, spec->autocfg.hp_pins[0], 0,
1191 AC_VERB_SET_UNSOLICITED_ENABLE,
1192 AC_USRSP_EN | ALC880_HP_EVENT);
1193 spec->unsol_event = alc_sku_unsol_event;
1194}
1195
Takashi Iwai6c819492009-08-10 18:47:44 +02001196static void alc_init_auto_mic(struct hda_codec *codec)
1197{
1198 struct alc_spec *spec = codec->spec;
1199 struct auto_pin_cfg *cfg = &spec->autocfg;
1200 hda_nid_t fixed, ext;
1201 int i;
1202
1203 /* there must be only two mic inputs exclusively */
1204 for (i = AUTO_PIN_LINE; i < AUTO_PIN_LAST; i++)
1205 if (cfg->input_pins[i])
1206 return;
1207
1208 fixed = ext = 0;
1209 for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++) {
1210 hda_nid_t nid = cfg->input_pins[i];
1211 unsigned int defcfg;
1212 if (!nid)
1213 return;
1214 defcfg = snd_hda_codec_get_pincfg(codec, nid);
1215 switch (get_defcfg_connect(defcfg)) {
1216 case AC_JACK_PORT_FIXED:
1217 if (fixed)
1218 return; /* already occupied */
1219 fixed = nid;
1220 break;
1221 case AC_JACK_PORT_COMPLEX:
1222 if (ext)
1223 return; /* already occupied */
1224 ext = nid;
1225 break;
1226 default:
1227 return; /* invalid entry */
1228 }
1229 }
1230 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},
1670/* Enable amplifiers */
1671 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
1672 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
Hector Martin018df412009-06-04 00:13:40 +02001673/* DMIC fix
1674 * This laptop has a stereo digital microphone. The mics are only 1cm apart
1675 * which makes the stereo useless. However, either the mic or the ALC889
1676 * makes the signal become a difference/sum signal instead of standard
1677 * stereo, which is annoying. So instead we flip this bit which makes the
1678 * codec replicate the sum signal to both channels, turning it into a
1679 * normal mono mic.
1680 */
1681/* DMIC_CONTROL? Init value = 0x0001 */
1682 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
1683 {0x20, AC_VERB_SET_PROC_COEF, 0x0003},
Hector Martin3b315d72009-06-02 10:54:19 +02001684 { }
1685};
1686
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001687static struct hda_input_mux alc888_2_capture_sources[2] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001688 /* Front mic only available on one ADC */
1689 {
1690 .num_items = 4,
1691 .items = {
1692 { "Mic", 0x0 },
1693 { "Line", 0x2 },
1694 { "CD", 0x4 },
1695 { "Front Mic", 0xb },
1696 },
1697 },
1698 {
1699 .num_items = 3,
1700 .items = {
1701 { "Mic", 0x0 },
1702 { "Line", 0x2 },
1703 { "CD", 0x4 },
1704 },
1705 }
1706};
1707
Tony Vroond2fd4b02009-06-21 00:40:10 +01001708static struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
1709 /* Interal mic only available on one ADC */
1710 {
Tony Vroon684a8842009-06-26 09:27:50 +01001711 .num_items = 5,
Tony Vroond2fd4b02009-06-21 00:40:10 +01001712 .items = {
1713 { "Ext Mic", 0x0 },
Tony Vroon684a8842009-06-26 09:27:50 +01001714 { "Line In", 0x2 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01001715 { "CD", 0x4 },
Tony Vroon684a8842009-06-26 09:27:50 +01001716 { "Input Mix", 0xa },
Tony Vroond2fd4b02009-06-21 00:40:10 +01001717 { "Int Mic", 0xb },
1718 },
1719 },
1720 {
Tony Vroon684a8842009-06-26 09:27:50 +01001721 .num_items = 4,
Tony Vroond2fd4b02009-06-21 00:40:10 +01001722 .items = {
1723 { "Ext Mic", 0x0 },
Tony Vroon684a8842009-06-26 09:27:50 +01001724 { "Line In", 0x2 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01001725 { "CD", 0x4 },
Tony Vroon684a8842009-06-26 09:27:50 +01001726 { "Input Mix", 0xa },
Tony Vroond2fd4b02009-06-21 00:40:10 +01001727 },
1728 }
1729};
1730
Hector Martin018df412009-06-04 00:13:40 +02001731static struct hda_input_mux alc889_capture_sources[3] = {
1732 /* Digital mic only available on first "ADC" */
1733 {
1734 .num_items = 5,
1735 .items = {
1736 { "Mic", 0x0 },
1737 { "Line", 0x2 },
1738 { "CD", 0x4 },
1739 { "Front Mic", 0xb },
1740 { "Input Mix", 0xa },
1741 },
1742 },
1743 {
1744 .num_items = 4,
1745 .items = {
1746 { "Mic", 0x0 },
1747 { "Line", 0x2 },
1748 { "CD", 0x4 },
1749 { "Input Mix", 0xa },
1750 },
1751 },
1752 {
1753 .num_items = 4,
1754 .items = {
1755 { "Mic", 0x0 },
1756 { "Line", 0x2 },
1757 { "CD", 0x4 },
1758 { "Input Mix", 0xa },
1759 },
1760 }
1761};
1762
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001763static struct snd_kcontrol_new alc888_base_mixer[] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001764 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1765 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
1766 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1767 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
1768 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
1769 HDA_OUTPUT),
1770 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1771 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1772 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1773 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
1774 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
1775 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1776 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1777 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1778 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1779 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1780 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
1781 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001782 { } /* end */
1783};
1784
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001785static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec)
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001786{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001787 struct alc_spec *spec = codec->spec;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001788
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001789 spec->autocfg.hp_pins[0] = 0x15;
1790 spec->autocfg.speaker_pins[0] = 0x14;
Łukasz Wojniłowicz7cef4cf2009-11-20 12:14:35 +01001791 spec->autocfg.speaker_pins[1] = 0x16;
1792 spec->autocfg.speaker_pins[2] = 0x17;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001793}
1794
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001795static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec)
Emilio López320d5922009-06-25 08:18:44 +02001796{
1797 struct alc_spec *spec = codec->spec;
1798
1799 spec->autocfg.hp_pins[0] = 0x15;
1800 spec->autocfg.speaker_pins[0] = 0x14;
1801 spec->autocfg.speaker_pins[1] = 0x16;
1802 spec->autocfg.speaker_pins[2] = 0x17;
Emilio López320d5922009-06-25 08:18:44 +02001803}
1804
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001805static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
Hector Martin3b315d72009-06-02 10:54:19 +02001806{
1807 struct alc_spec *spec = codec->spec;
1808
1809 spec->autocfg.hp_pins[0] = 0x15;
1810 spec->autocfg.speaker_pins[0] = 0x14;
1811 spec->autocfg.speaker_pins[1] = 0x16;
1812 spec->autocfg.speaker_pins[2] = 0x1b;
Hector Martin3b315d72009-06-02 10:54:19 +02001813}
1814
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001815/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001816 * ALC880 3-stack model
1817 *
1818 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001819 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
1820 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 */
1822
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001823static hda_nid_t alc880_dac_nids[4] = {
1824 /* front, rear, clfe, rear_surr */
1825 0x02, 0x05, 0x04, 0x03
1826};
1827
1828static hda_nid_t alc880_adc_nids[3] = {
1829 /* ADC0-2 */
1830 0x07, 0x08, 0x09,
1831};
1832
1833/* The datasheet says the node 0x07 is connected from inputs,
1834 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +01001835 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001837static hda_nid_t alc880_adc_nids_alt[2] = {
1838 /* ADC1-2 */
1839 0x08, 0x09,
1840};
1841
1842#define ALC880_DIGOUT_NID 0x06
1843#define ALC880_DIGIN_NID 0x0a
1844
1845static struct hda_input_mux alc880_capture_source = {
1846 .num_items = 4,
1847 .items = {
1848 { "Mic", 0x0 },
1849 { "Front Mic", 0x3 },
1850 { "Line", 0x2 },
1851 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001853};
1854
1855/* channel source setting (2/6 channel selection for 3-stack) */
1856/* 2ch mode */
1857static struct hda_verb alc880_threestack_ch2_init[] = {
1858 /* set line-in to input, mute it */
1859 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1860 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1861 /* set mic-in to input vref 80%, mute it */
1862 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1863 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 { } /* end */
1865};
1866
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001867/* 6ch mode */
1868static struct hda_verb alc880_threestack_ch6_init[] = {
1869 /* set line-in to output, unmute it */
1870 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1871 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1872 /* set mic-in to output, unmute it */
1873 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1874 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1875 { } /* end */
1876};
1877
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001878static struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001879 { 2, alc880_threestack_ch2_init },
1880 { 6, alc880_threestack_ch6_init },
1881};
1882
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001883static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001884 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001885 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001886 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001887 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001888 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1889 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001890 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1891 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1893 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1894 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1895 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1896 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1897 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1898 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
1899 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001901 {
1902 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1903 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001904 .info = alc_ch_mode_info,
1905 .get = alc_ch_mode_get,
1906 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001907 },
1908 { } /* end */
1909};
1910
1911/* capture mixer elements */
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001912static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
1913 struct snd_ctl_elem_info *uinfo)
1914{
1915 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1916 struct alc_spec *spec = codec->spec;
1917 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001918
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001919 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001920 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
1921 HDA_INPUT);
1922 err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001923 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001924 return err;
1925}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001927static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
1928 unsigned int size, unsigned int __user *tlv)
1929{
1930 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1931 struct alc_spec *spec = codec->spec;
1932 int err;
1933
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001934 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001935 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
1936 HDA_INPUT);
1937 err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001938 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001939 return err;
1940}
1941
1942typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
1943 struct snd_ctl_elem_value *ucontrol);
1944
1945static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
1946 struct snd_ctl_elem_value *ucontrol,
1947 getput_call_t func)
1948{
1949 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1950 struct alc_spec *spec = codec->spec;
1951 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1952 int err;
1953
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001954 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001955 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[adc_idx],
1956 3, 0, HDA_INPUT);
1957 err = func(kcontrol, ucontrol);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001958 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001959 return err;
1960}
1961
1962static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
1963 struct snd_ctl_elem_value *ucontrol)
1964{
1965 return alc_cap_getput_caller(kcontrol, ucontrol,
1966 snd_hda_mixer_amp_volume_get);
1967}
1968
1969static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
1970 struct snd_ctl_elem_value *ucontrol)
1971{
1972 return alc_cap_getput_caller(kcontrol, ucontrol,
1973 snd_hda_mixer_amp_volume_put);
1974}
1975
1976/* capture mixer elements */
1977#define alc_cap_sw_info snd_ctl_boolean_stereo_info
1978
1979static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
1980 struct snd_ctl_elem_value *ucontrol)
1981{
1982 return alc_cap_getput_caller(kcontrol, ucontrol,
1983 snd_hda_mixer_amp_switch_get);
1984}
1985
1986static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
1987 struct snd_ctl_elem_value *ucontrol)
1988{
1989 return alc_cap_getput_caller(kcontrol, ucontrol,
1990 snd_hda_mixer_amp_switch_put);
1991}
1992
Takashi Iwaia23b6882009-03-23 15:21:36 +01001993#define _DEFINE_CAPMIX(num) \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001994 { \
1995 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1996 .name = "Capture Switch", \
1997 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
1998 .count = num, \
1999 .info = alc_cap_sw_info, \
2000 .get = alc_cap_sw_get, \
2001 .put = alc_cap_sw_put, \
2002 }, \
2003 { \
2004 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2005 .name = "Capture Volume", \
2006 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
2007 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
2008 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
2009 .count = num, \
2010 .info = alc_cap_vol_info, \
2011 .get = alc_cap_vol_get, \
2012 .put = alc_cap_vol_put, \
2013 .tlv = { .c = alc_cap_vol_tlv }, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002014 }
2015
2016#define _DEFINE_CAPSRC(num) \
Takashi Iwai3c3e9892008-10-31 17:48:56 +01002017 { \
2018 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2019 /* .name = "Capture Source", */ \
2020 .name = "Input Source", \
2021 .count = num, \
2022 .info = alc_mux_enum_info, \
2023 .get = alc_mux_enum_get, \
2024 .put = alc_mux_enum_put, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002025 }
2026
2027#define DEFINE_CAPMIX(num) \
2028static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
2029 _DEFINE_CAPMIX(num), \
2030 _DEFINE_CAPSRC(num), \
2031 { } /* end */ \
2032}
2033
2034#define DEFINE_CAPMIX_NOSRC(num) \
2035static struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
2036 _DEFINE_CAPMIX(num), \
2037 { } /* end */ \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002038}
2039
2040/* up to three ADCs */
2041DEFINE_CAPMIX(1);
2042DEFINE_CAPMIX(2);
2043DEFINE_CAPMIX(3);
Takashi Iwaia23b6882009-03-23 15:21:36 +01002044DEFINE_CAPMIX_NOSRC(1);
2045DEFINE_CAPMIX_NOSRC(2);
2046DEFINE_CAPMIX_NOSRC(3);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002047
2048/*
2049 * ALC880 5-stack model
2050 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002051 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
2052 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002053 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
2054 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
2055 */
2056
2057/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002058static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002059 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002060 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 { } /* end */
2062};
2063
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002064/* channel source setting (6/8 channel selection for 5-stack) */
2065/* 6ch mode */
2066static struct hda_verb alc880_fivestack_ch6_init[] = {
2067 /* set line-in to input, mute it */
2068 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2069 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002070 { } /* end */
2071};
2072
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002073/* 8ch mode */
2074static struct hda_verb alc880_fivestack_ch8_init[] = {
2075 /* set line-in to output, unmute it */
2076 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2077 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2078 { } /* end */
2079};
2080
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002081static struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002082 { 6, alc880_fivestack_ch6_init },
2083 { 8, alc880_fivestack_ch8_init },
2084};
2085
2086
2087/*
2088 * ALC880 6-stack model
2089 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002090 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
2091 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002092 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
2093 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
2094 */
2095
2096static hda_nid_t alc880_6st_dac_nids[4] = {
2097 /* front, rear, clfe, rear_surr */
2098 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002099};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002100
2101static struct hda_input_mux alc880_6stack_capture_source = {
2102 .num_items = 4,
2103 .items = {
2104 { "Mic", 0x0 },
2105 { "Front Mic", 0x1 },
2106 { "Line", 0x2 },
2107 { "CD", 0x4 },
2108 },
2109};
2110
2111/* fixed 8-channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002112static struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002113 { 8, NULL },
2114};
2115
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002116static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002117 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002118 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002119 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002120 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002121 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2122 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002123 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2124 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002125 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002126 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002127 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2128 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2129 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2130 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2131 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2132 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2133 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2134 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002135 {
2136 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2137 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002138 .info = alc_ch_mode_info,
2139 .get = alc_ch_mode_get,
2140 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02002141 },
2142 { } /* end */
2143};
2144
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002145
2146/*
2147 * ALC880 W810 model
2148 *
2149 * W810 has rear IO for:
2150 * Front (DAC 02)
2151 * Surround (DAC 03)
2152 * Center/LFE (DAC 04)
2153 * Digital out (06)
2154 *
2155 * The system also has a pair of internal speakers, and a headphone jack.
2156 * These are both connected to Line2 on the codec, hence to DAC 02.
Kailang Yangea1fb292008-08-26 12:58:38 +02002157 *
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002158 * There is a variable resistor to control the speaker or headphone
2159 * volume. This is a hardware-only device without a software API.
2160 *
2161 * Plugging headphones in will disable the internal speakers. This is
2162 * implemented in hardware, not via the driver using jack sense. In
2163 * a similar fashion, plugging into the rear socket marked "front" will
2164 * disable both the speakers and headphones.
2165 *
2166 * For input, there's a microphone jack, and an "audio in" jack.
2167 * These may not do anything useful with this driver yet, because I
2168 * haven't setup any initialization verbs for these yet...
2169 */
2170
2171static hda_nid_t alc880_w810_dac_nids[3] = {
2172 /* front, rear/surround, clfe */
2173 0x02, 0x03, 0x04
2174};
2175
2176/* fixed 6 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002177static struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002178 { 6, NULL }
2179};
2180
2181/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002182static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002183 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002184 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002185 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002186 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002187 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2188 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002189 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2190 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002191 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
2192 { } /* end */
2193};
2194
2195
2196/*
2197 * Z710V model
2198 *
2199 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002200 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
2201 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002202 */
2203
2204static hda_nid_t alc880_z71v_dac_nids[1] = {
2205 0x02
2206};
2207#define ALC880_Z71V_HP_DAC 0x03
2208
2209/* fixed 2 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002210static struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002211 { 2, NULL }
2212};
2213
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002214static struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002215 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002216 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002217 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002218 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002219 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2220 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2221 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2222 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2223 { } /* end */
2224};
2225
2226
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002227/*
2228 * ALC880 F1734 model
2229 *
2230 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
2231 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
2232 */
2233
2234static hda_nid_t alc880_f1734_dac_nids[1] = {
2235 0x03
2236};
2237#define ALC880_F1734_HP_DAC 0x02
2238
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002239static struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002240 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002241 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01002242 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2243 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002244 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2245 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01002246 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2247 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002248 { } /* end */
2249};
2250
Takashi Iwai937b4162008-02-11 14:52:36 +01002251static struct hda_input_mux alc880_f1734_capture_source = {
2252 .num_items = 2,
2253 .items = {
2254 { "Mic", 0x1 },
2255 { "CD", 0x4 },
2256 },
2257};
2258
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002259
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002260/*
2261 * ALC880 ASUS model
2262 *
2263 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
2264 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
2265 * Mic = 0x18, Line = 0x1a
2266 */
2267
2268#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
2269#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
2270
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002271static struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002272 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002273 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002274 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002275 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002276 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2277 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002278 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2279 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002280 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2281 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2282 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2283 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2284 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2285 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002286 {
2287 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2288 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002289 .info = alc_ch_mode_info,
2290 .get = alc_ch_mode_get,
2291 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02002292 },
2293 { } /* end */
2294};
2295
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002296/*
2297 * ALC880 ASUS W1V model
2298 *
2299 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
2300 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
2301 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
2302 */
2303
2304/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002305static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002306 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
2307 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002308 { } /* end */
2309};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002310
Kailang Yangdf694da2005-12-05 19:42:22 +01002311/* TCL S700 */
2312static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
2313 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2314 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
2315 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
2316 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
2317 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
2318 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
2319 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
2320 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
2321 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01002322 { } /* end */
2323};
2324
Kailang Yangccc656c2006-10-17 12:32:26 +02002325/* Uniwill */
2326static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002327 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2328 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2329 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2330 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002331 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2332 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2333 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2334 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2335 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2336 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2337 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2338 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2339 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2340 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2341 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2342 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002343 {
2344 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2345 .name = "Channel Mode",
2346 .info = alc_ch_mode_info,
2347 .get = alc_ch_mode_get,
2348 .put = alc_ch_mode_put,
2349 },
2350 { } /* end */
2351};
2352
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002353static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
2354 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2355 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2356 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2357 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
2358 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2359 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2360 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2361 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2362 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2363 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
2364 { } /* end */
2365};
2366
Kailang Yangccc656c2006-10-17 12:32:26 +02002367static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002368 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2369 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2370 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2371 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002372 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2373 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2374 { } /* end */
2375};
2376
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01002378 * virtual master controls
2379 */
2380
2381/*
2382 * slave controls for virtual master
2383 */
2384static const char *alc_slave_vols[] = {
2385 "Front Playback Volume",
2386 "Surround Playback Volume",
2387 "Center Playback Volume",
2388 "LFE Playback Volume",
2389 "Side Playback Volume",
2390 "Headphone Playback Volume",
2391 "Speaker Playback Volume",
2392 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002393 "Line-Out Playback Volume",
Takashi Iwai26f5df22008-11-03 17:39:46 +01002394 "PCM Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002395 NULL,
2396};
2397
2398static const char *alc_slave_sws[] = {
2399 "Front Playback Switch",
2400 "Surround Playback Switch",
2401 "Center Playback Switch",
2402 "LFE Playback Switch",
2403 "Side Playback Switch",
2404 "Headphone Playback Switch",
2405 "Speaker Playback Switch",
2406 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01002407 "IEC958 Playback Switch",
Takashi Iwai23033b22009-12-08 12:36:52 +01002408 "Line-Out Playback Switch",
2409 "PCM Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002410 NULL,
2411};
2412
2413/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002414 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 */
Takashi Iwai603c4012008-07-30 15:01:44 +02002416
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002417#define NID_MAPPING (-1)
2418
2419#define SUBDEV_SPEAKER_ (0 << 6)
2420#define SUBDEV_HP_ (1 << 6)
2421#define SUBDEV_LINE_ (2 << 6)
2422#define SUBDEV_SPEAKER(x) (SUBDEV_SPEAKER_ | ((x) & 0x3f))
2423#define SUBDEV_HP(x) (SUBDEV_HP_ | ((x) & 0x3f))
2424#define SUBDEV_LINE(x) (SUBDEV_LINE_ | ((x) & 0x3f))
2425
Takashi Iwai603c4012008-07-30 15:01:44 +02002426static void alc_free_kctls(struct hda_codec *codec);
2427
Takashi Iwai67d634c2009-11-16 15:35:59 +01002428#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002429/* additional beep mixers; the actual parameters are overwritten at build */
2430static struct snd_kcontrol_new alc_beep_mixer[] = {
2431 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
Jaroslav Kysela123c07a2009-10-21 14:48:23 +02002432 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002433 { } /* end */
2434};
Takashi Iwai67d634c2009-11-16 15:35:59 +01002435#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002436
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437static int alc_build_controls(struct hda_codec *codec)
2438{
2439 struct alc_spec *spec = codec->spec;
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002440 struct snd_kcontrol *kctl;
2441 struct snd_kcontrol_new *knew;
2442 int i, j, err;
2443 unsigned int u;
2444 hda_nid_t nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445
2446 for (i = 0; i < spec->num_mixers; i++) {
2447 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
2448 if (err < 0)
2449 return err;
2450 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002451 if (spec->cap_mixer) {
2452 err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
2453 if (err < 0)
2454 return err;
2455 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002457 err = snd_hda_create_spdif_out_ctls(codec,
2458 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 if (err < 0)
2460 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002461 if (!spec->no_analog) {
2462 err = snd_hda_create_spdif_share_sw(codec,
2463 &spec->multiout);
2464 if (err < 0)
2465 return err;
2466 spec->multiout.share_spdif = 1;
2467 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 }
2469 if (spec->dig_in_nid) {
2470 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
2471 if (err < 0)
2472 return err;
2473 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01002474
Takashi Iwai67d634c2009-11-16 15:35:59 +01002475#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002476 /* create beep controls if needed */
2477 if (spec->beep_amp) {
2478 struct snd_kcontrol_new *knew;
2479 for (knew = alc_beep_mixer; knew->name; knew++) {
2480 struct snd_kcontrol *kctl;
2481 kctl = snd_ctl_new1(knew, codec);
2482 if (!kctl)
2483 return -ENOMEM;
2484 kctl->private_value = spec->beep_amp;
Jaroslav Kysela3911a4c2009-11-11 13:43:01 +01002485 err = snd_hda_ctl_add(codec,
2486 get_amp_nid_(spec->beep_amp), kctl);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002487 if (err < 0)
2488 return err;
2489 }
2490 }
Takashi Iwai67d634c2009-11-16 15:35:59 +01002491#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002492
Takashi Iwai2134ea42008-01-10 16:53:55 +01002493 /* if we have no master control, let's create it */
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002494 if (!spec->no_analog &&
2495 !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002496 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01002497 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002498 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01002499 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002500 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01002501 if (err < 0)
2502 return err;
2503 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002504 if (!spec->no_analog &&
2505 !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002506 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
2507 NULL, alc_slave_sws);
2508 if (err < 0)
2509 return err;
2510 }
2511
Takashi Iwai603c4012008-07-30 15:01:44 +02002512 alc_free_kctls(codec); /* no longer needed */
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002513
2514 /* assign Capture Source enums to NID */
2515 kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
2516 if (!kctl)
2517 kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
2518 for (i = 0; kctl && i < kctl->count; i++) {
2519 err = snd_hda_add_nids(codec, kctl, i, spec->capsrc_nids,
2520 spec->input_mux->num_items);
2521 if (err < 0)
2522 return err;
2523 }
2524 if (spec->cap_mixer) {
2525 const char *kname = kctl ? kctl->id.name : NULL;
2526 for (knew = spec->cap_mixer; knew->name; knew++) {
2527 if (kname && strcmp(knew->name, kname) == 0)
2528 continue;
2529 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
2530 for (i = 0; kctl && i < kctl->count; i++) {
2531 err = snd_hda_add_nid(codec, kctl, i,
2532 spec->adc_nids[i]);
2533 if (err < 0)
2534 return err;
2535 }
2536 }
2537 }
2538
2539 /* other nid->control mapping */
2540 for (i = 0; i < spec->num_mixers; i++) {
2541 for (knew = spec->mixers[i]; knew->name; knew++) {
2542 if (knew->iface != NID_MAPPING)
2543 continue;
2544 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
2545 if (kctl == NULL)
2546 continue;
2547 u = knew->subdevice;
2548 for (j = 0; j < 4; j++, u >>= 8) {
2549 nid = u & 0x3f;
2550 if (nid == 0)
2551 continue;
2552 switch (u & 0xc0) {
2553 case SUBDEV_SPEAKER_:
2554 nid = spec->autocfg.speaker_pins[nid];
2555 break;
2556 case SUBDEV_LINE_:
2557 nid = spec->autocfg.line_out_pins[nid];
2558 break;
2559 case SUBDEV_HP_:
2560 nid = spec->autocfg.hp_pins[nid];
2561 break;
2562 default:
2563 continue;
2564 }
2565 err = snd_hda_add_nid(codec, kctl, 0, nid);
2566 if (err < 0)
2567 return err;
2568 }
2569 u = knew->private_value;
2570 for (j = 0; j < 4; j++, u >>= 8) {
2571 nid = u & 0xff;
2572 if (nid == 0)
2573 continue;
2574 err = snd_hda_add_nid(codec, kctl, 0, nid);
2575 if (err < 0)
2576 return err;
2577 }
2578 }
2579 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 return 0;
2581}
2582
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002583
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584/*
2585 * initialize the codec volumes, etc
2586 */
2587
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002588/*
2589 * generic initialization of ADC, input mixers and output mixers
2590 */
2591static struct hda_verb alc880_volume_init_verbs[] = {
2592 /*
2593 * Unmute ADC0-2 and set the default input to mic-in
2594 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002595 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002596 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002597 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002598 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002599 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002600 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002602 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2603 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002604 * Note: PASD motherboards uses the Line In 2 as the input for front
2605 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002607 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02002608 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2609 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2610 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2611 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2612 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2613 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2614 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002616 /*
2617 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002619 /* set vol=0 to output mixers */
2620 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2621 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2622 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2623 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2624 /* set up input amps for analog loopback */
2625 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002626 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2627 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002628 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2629 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002630 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2631 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002632 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2633 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634
2635 { }
2636};
2637
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002638/*
2639 * 3-stack pin configuration:
2640 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
2641 */
2642static struct hda_verb alc880_pin_3stack_init_verbs[] = {
2643 /*
2644 * preset connection lists of input pins
2645 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
2646 */
2647 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
2648 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2649 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
2650
2651 /*
2652 * Set pin mode and muting
2653 */
2654 /* set front pin widgets 0x14 for output */
2655 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2656 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2657 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2658 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2659 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2660 /* Mic2 (as headphone out) for HP output */
2661 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2662 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2663 /* Line In pin widget for input */
2664 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2665 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2666 /* Line2 (as front mic) pin widget for input and vref at 80% */
2667 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2668 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2669 /* CD pin widget for input */
2670 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2671
2672 { }
2673};
2674
2675/*
2676 * 5-stack pin configuration:
2677 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
2678 * line-in/side = 0x1a, f-mic = 0x1b
2679 */
2680static struct hda_verb alc880_pin_5stack_init_verbs[] = {
2681 /*
2682 * preset connection lists of input pins
2683 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
2684 */
2685 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2686 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
2687
2688 /*
2689 * Set pin mode and muting
2690 */
2691 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02002692 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2693 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2694 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2695 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002696 /* unmute pins for output (no gain on this amp) */
2697 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2698 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2699 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2700 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2701
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02002703 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002704 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2705 /* Mic2 (as headphone out) for HP output */
2706 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02002707 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002708 /* Line In pin widget for input */
2709 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2710 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2711 /* Line2 (as front mic) pin widget for input and vref at 80% */
2712 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2713 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2714 /* CD pin widget for input */
2715 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716
2717 { }
2718};
2719
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002720/*
2721 * W810 pin configuration:
2722 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
2723 */
2724static struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 /* hphone/speaker input selector: front DAC */
2726 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
2727
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002728 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2729 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2730 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2731 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2732 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2733 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2734
2735 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02002736 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 { }
2739};
2740
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002741/*
2742 * Z71V pin configuration:
2743 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
2744 */
2745static struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002746 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002747 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02002748 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002749 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002750
Takashi Iwai16ded522005-06-10 19:58:24 +02002751 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002752 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02002753 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002754 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002755
2756 { }
2757};
2758
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002759/*
2760 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002761 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
2762 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002763 */
2764static struct hda_verb alc880_pin_6stack_init_verbs[] = {
2765 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2766
Takashi Iwai16ded522005-06-10 19:58:24 +02002767 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002768 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002769 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002770 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002771 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002772 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002773 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002774 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2775
Takashi Iwai16ded522005-06-10 19:58:24 +02002776 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002777 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002778 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002779 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002780 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002781 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002782 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02002783 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002784 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02002785
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002786 { }
2787};
Takashi Iwai16ded522005-06-10 19:58:24 +02002788
Kailang Yangccc656c2006-10-17 12:32:26 +02002789/*
2790 * Uniwill pin configuration:
2791 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
2792 * line = 0x1a
2793 */
2794static struct hda_verb alc880_uniwill_init_verbs[] = {
2795 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2796
2797 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2798 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2799 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2800 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2801 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2802 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2803 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2804 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2805 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2806 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2807 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2808 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2809 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2810 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2811
2812 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2813 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2814 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2815 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2816 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2817 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2818 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
2819 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
2820 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2821
2822 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2823 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
2824
2825 { }
2826};
2827
2828/*
2829* Uniwill P53
Kailang Yangea1fb292008-08-26 12:58:38 +02002830* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
Kailang Yangccc656c2006-10-17 12:32:26 +02002831 */
2832static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
2833 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2834
2835 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2836 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2837 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2838 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2839 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2840 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2841 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2842 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2843 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2844 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2845 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2846 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2847
2848 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2849 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2850 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2851 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2852 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2853 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2854
2855 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2856 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
2857
2858 { }
2859};
2860
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002861static struct hda_verb alc880_beep_init_verbs[] = {
2862 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
2863 { }
2864};
2865
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002866/* auto-toggle front mic */
2867static void alc880_uniwill_mic_automute(struct hda_codec *codec)
2868{
2869 unsigned int present;
2870 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02002871
Wu Fengguang864f92b2009-11-18 12:38:02 +08002872 present = snd_hda_jack_detect(codec, 0x18);
Takashi Iwai47fd8302007-08-10 17:11:07 +02002873 bits = present ? HDA_AMP_MUTE : 0;
2874 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002875}
2876
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002877static void alc880_uniwill_setup(struct hda_codec *codec)
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002878{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002879 struct alc_spec *spec = codec->spec;
2880
2881 spec->autocfg.hp_pins[0] = 0x14;
2882 spec->autocfg.speaker_pins[0] = 0x15;
2883 spec->autocfg.speaker_pins[0] = 0x16;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002884}
2885
2886static void alc880_uniwill_init_hook(struct hda_codec *codec)
2887{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002888 alc_automute_amp(codec);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002889 alc880_uniwill_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02002890}
2891
2892static void alc880_uniwill_unsol_event(struct hda_codec *codec,
2893 unsigned int res)
2894{
2895 /* Looks like the unsol event is incompatible with the standard
2896 * definition. 4bit tag is placed at 28 bit!
2897 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002898 switch (res >> 28) {
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002899 case ALC880_MIC_EVENT:
2900 alc880_uniwill_mic_automute(codec);
2901 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002902 default:
2903 alc_automute_amp_unsol_event(codec, res);
2904 break;
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002905 }
Kailang Yangccc656c2006-10-17 12:32:26 +02002906}
2907
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002908static void alc880_uniwill_p53_setup(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02002909{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002910 struct alc_spec *spec = codec->spec;
Kailang Yangccc656c2006-10-17 12:32:26 +02002911
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002912 spec->autocfg.hp_pins[0] = 0x14;
2913 spec->autocfg.speaker_pins[0] = 0x15;
Kailang Yangccc656c2006-10-17 12:32:26 +02002914}
2915
2916static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
2917{
2918 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02002919
Kailang Yangccc656c2006-10-17 12:32:26 +02002920 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02002921 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
2922 present &= HDA_AMP_VOLMASK;
2923 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
2924 HDA_AMP_VOLMASK, present);
2925 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
2926 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02002927}
Takashi Iwai47fd8302007-08-10 17:11:07 +02002928
Kailang Yangccc656c2006-10-17 12:32:26 +02002929static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
2930 unsigned int res)
2931{
2932 /* Looks like the unsol event is incompatible with the standard
2933 * definition. 4bit tag is placed at 28 bit!
2934 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002935 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02002936 alc880_uniwill_p53_dcvol_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002937 else
2938 alc_automute_amp_unsol_event(codec, res);
Kailang Yangccc656c2006-10-17 12:32:26 +02002939}
2940
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002941/*
2942 * F1734 pin configuration:
2943 * HP = 0x14, speaker-out = 0x15, mic = 0x18
2944 */
2945static struct hda_verb alc880_pin_f1734_init_verbs[] = {
Michael Gruberee7a9c72008-03-10 11:30:59 +01002946 {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002947 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
2948 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
2949 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
2950 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
2951
2952 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2953 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2954 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2955 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2956
2957 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2958 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Michael Gruberee7a9c72008-03-10 11:30:59 +01002959 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002960 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2961 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2962 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2963 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2964 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2965 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02002966
Takashi Iwai937b4162008-02-11 14:52:36 +01002967 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
2968 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
2969
Takashi Iwai16ded522005-06-10 19:58:24 +02002970 { }
2971};
2972
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002973/*
2974 * ASUS pin configuration:
2975 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
2976 */
2977static struct hda_verb alc880_pin_asus_init_verbs[] = {
2978 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
2979 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
2980 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
2981 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
2982
2983 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2984 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2985 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2986 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2987 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2988 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2989 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2990 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2991
2992 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2993 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2994 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2995 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2996 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2997 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2998 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2999 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3000 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02003001
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003002 { }
3003};
3004
3005/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003006#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
3007#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
David Heidelberger64a8be72009-06-08 16:15:18 +02003008#define alc880_gpio3_init_verbs alc_gpio3_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003009
Kailang Yangdf694da2005-12-05 19:42:22 +01003010/* Clevo m520g init */
3011static struct hda_verb alc880_pin_clevo_init_verbs[] = {
3012 /* headphone output */
3013 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3014 /* line-out */
3015 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3016 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3017 /* Line-in */
3018 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3019 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3020 /* CD */
3021 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3022 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3023 /* Mic1 (rear panel) */
3024 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3025 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3026 /* Mic2 (front panel) */
3027 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3028 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3029 /* headphone */
3030 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3031 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3032 /* change to EAPD mode */
3033 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3034 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3035
3036 { }
3037};
3038
3039static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02003040 /* change to EAPD mode */
3041 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3042 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3043
Kailang Yangdf694da2005-12-05 19:42:22 +01003044 /* Headphone output */
3045 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3046 /* Front output*/
3047 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3048 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
3049
3050 /* Line In pin widget for input */
3051 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3052 /* CD pin widget for input */
3053 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3054 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3055 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3056
3057 /* change to EAPD mode */
3058 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3059 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
3060
3061 { }
3062};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003063
3064/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003065 * LG m1 express dual
3066 *
3067 * Pin assignment:
3068 * Rear Line-In/Out (blue): 0x14
3069 * Build-in Mic-In: 0x15
3070 * Speaker-out: 0x17
3071 * HP-Out (green): 0x1b
3072 * Mic-In/Out (red): 0x19
3073 * SPDIF-Out: 0x1e
3074 */
3075
3076/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
3077static hda_nid_t alc880_lg_dac_nids[3] = {
3078 0x05, 0x02, 0x03
3079};
3080
3081/* seems analog CD is not working */
3082static struct hda_input_mux alc880_lg_capture_source = {
3083 .num_items = 3,
3084 .items = {
3085 { "Mic", 0x1 },
3086 { "Line", 0x5 },
3087 { "Internal Mic", 0x6 },
3088 },
3089};
3090
3091/* 2,4,6 channel modes */
3092static struct hda_verb alc880_lg_ch2_init[] = {
3093 /* set line-in and mic-in to input */
3094 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
3095 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3096 { }
3097};
3098
3099static struct hda_verb alc880_lg_ch4_init[] = {
3100 /* set line-in to out and mic-in to input */
3101 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3102 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3103 { }
3104};
3105
3106static struct hda_verb alc880_lg_ch6_init[] = {
3107 /* set line-in and mic-in to output */
3108 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3109 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3110 { }
3111};
3112
3113static struct hda_channel_mode alc880_lg_ch_modes[3] = {
3114 { 2, alc880_lg_ch2_init },
3115 { 4, alc880_lg_ch4_init },
3116 { 6, alc880_lg_ch6_init },
3117};
3118
3119static struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003120 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
3121 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003122 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3123 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
3124 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
3125 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
3126 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
3127 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
3128 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3129 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
3130 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
3131 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
3132 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
3133 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
3134 {
3135 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3136 .name = "Channel Mode",
3137 .info = alc_ch_mode_info,
3138 .get = alc_ch_mode_get,
3139 .put = alc_ch_mode_put,
3140 },
3141 { } /* end */
3142};
3143
3144static struct hda_verb alc880_lg_init_verbs[] = {
3145 /* set capture source to mic-in */
3146 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3147 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3148 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3149 /* mute all amp mixer inputs */
3150 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02003151 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
3152 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003153 /* line-in to input */
3154 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3155 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3156 /* built-in mic */
3157 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3158 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3159 /* speaker-out */
3160 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3161 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3162 /* mic-in to input */
3163 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3164 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3165 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3166 /* HP-out */
3167 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
3168 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3169 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3170 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003171 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003172 { }
3173};
3174
3175/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003176static void alc880_lg_setup(struct hda_codec *codec)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003177{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003178 struct alc_spec *spec = codec->spec;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003179
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003180 spec->autocfg.hp_pins[0] = 0x1b;
3181 spec->autocfg.speaker_pins[0] = 0x17;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003182}
3183
3184/*
Takashi Iwaid6815182006-03-23 16:06:23 +01003185 * LG LW20
3186 *
3187 * Pin assignment:
3188 * Speaker-out: 0x14
3189 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003190 * Built-in Mic-In: 0x19
3191 * Line-In: 0x1b
3192 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01003193 * SPDIF-Out: 0x1e
3194 */
3195
Takashi Iwaid6815182006-03-23 16:06:23 +01003196static struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003197 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01003198 .items = {
3199 { "Mic", 0x0 },
3200 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003201 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003202 },
3203};
3204
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003205#define alc880_lg_lw_modes alc880_threestack_modes
3206
Takashi Iwaid6815182006-03-23 16:06:23 +01003207static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003208 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3209 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
3210 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
3211 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
3212 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
3213 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
3214 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
3215 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
3216 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
3217 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01003218 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3219 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3220 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
3221 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003222 {
3223 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3224 .name = "Channel Mode",
3225 .info = alc_ch_mode_info,
3226 .get = alc_ch_mode_get,
3227 .put = alc_ch_mode_put,
3228 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003229 { } /* end */
3230};
3231
3232static struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003233 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3234 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
3235 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
3236
Takashi Iwaid6815182006-03-23 16:06:23 +01003237 /* set capture source to mic-in */
3238 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3239 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3240 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02003241 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01003242 /* speaker-out */
3243 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3244 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3245 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01003246 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3247 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3248 /* mic-in to input */
3249 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3250 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3251 /* built-in mic */
3252 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3253 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3254 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003255 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaid6815182006-03-23 16:06:23 +01003256 { }
3257};
3258
3259/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003260static void alc880_lg_lw_setup(struct hda_codec *codec)
Takashi Iwaid6815182006-03-23 16:06:23 +01003261{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003262 struct alc_spec *spec = codec->spec;
Takashi Iwaid6815182006-03-23 16:06:23 +01003263
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003264 spec->autocfg.hp_pins[0] = 0x1b;
3265 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid6815182006-03-23 16:06:23 +01003266}
3267
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003268static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
3269 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3270 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
3271 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3272 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3273 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3274 HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
3275 { } /* end */
3276};
3277
3278static struct hda_input_mux alc880_medion_rim_capture_source = {
3279 .num_items = 2,
3280 .items = {
3281 { "Mic", 0x0 },
3282 { "Internal Mic", 0x1 },
3283 },
3284};
3285
3286static struct hda_verb alc880_medion_rim_init_verbs[] = {
3287 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3288
3289 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3290 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3291
3292 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3293 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3294 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3295 /* Mic2 (as headphone out) for HP output */
3296 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3297 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3298 /* Internal Speaker */
3299 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3300 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3301
3302 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3303 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3304
3305 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3306 { }
3307};
3308
3309/* toggle speaker-output according to the hp-jack state */
3310static void alc880_medion_rim_automute(struct hda_codec *codec)
3311{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003312 struct alc_spec *spec = codec->spec;
3313 alc_automute_amp(codec);
3314 /* toggle EAPD */
3315 if (spec->jack_present)
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003316 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
3317 else
3318 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
3319}
3320
3321static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
3322 unsigned int res)
3323{
3324 /* Looks like the unsol event is incompatible with the standard
3325 * definition. 4bit tag is placed at 28 bit!
3326 */
3327 if ((res >> 28) == ALC880_HP_EVENT)
3328 alc880_medion_rim_automute(codec);
3329}
3330
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003331static void alc880_medion_rim_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003332{
3333 struct alc_spec *spec = codec->spec;
3334
3335 spec->autocfg.hp_pins[0] = 0x14;
3336 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003337}
3338
Takashi Iwaicb53c622007-08-10 17:21:45 +02003339#ifdef CONFIG_SND_HDA_POWER_SAVE
3340static struct hda_amp_list alc880_loopbacks[] = {
3341 { 0x0b, HDA_INPUT, 0 },
3342 { 0x0b, HDA_INPUT, 1 },
3343 { 0x0b, HDA_INPUT, 2 },
3344 { 0x0b, HDA_INPUT, 3 },
3345 { 0x0b, HDA_INPUT, 4 },
3346 { } /* end */
3347};
3348
3349static struct hda_amp_list alc880_lg_loopbacks[] = {
3350 { 0x0b, HDA_INPUT, 1 },
3351 { 0x0b, HDA_INPUT, 6 },
3352 { 0x0b, HDA_INPUT, 7 },
3353 { } /* end */
3354};
3355#endif
3356
Takashi Iwaid6815182006-03-23 16:06:23 +01003357/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003358 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003359 */
Takashi Iwai16ded522005-06-10 19:58:24 +02003360
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361static int alc_init(struct hda_codec *codec)
3362{
3363 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003364 unsigned int i;
3365
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02003366 alc_fix_pll(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02003367 alc_auto_init_amp(codec, spec->init_amp);
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02003368
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003369 for (i = 0; i < spec->num_init_verbs; i++)
3370 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003371
3372 if (spec->init_hook)
3373 spec->init_hook(codec);
3374
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 return 0;
3376}
3377
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003378static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
3379{
3380 struct alc_spec *spec = codec->spec;
3381
3382 if (spec->unsol_event)
3383 spec->unsol_event(codec, res);
3384}
3385
Takashi Iwaicb53c622007-08-10 17:21:45 +02003386#ifdef CONFIG_SND_HDA_POWER_SAVE
3387static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
3388{
3389 struct alc_spec *spec = codec->spec;
3390 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
3391}
3392#endif
3393
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394/*
3395 * Analog playback callbacks
3396 */
3397static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
3398 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003399 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400{
3401 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01003402 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
3403 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404}
3405
3406static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
3407 struct hda_codec *codec,
3408 unsigned int stream_tag,
3409 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003410 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411{
3412 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003413 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
3414 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415}
3416
3417static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3418 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003419 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420{
3421 struct alc_spec *spec = codec->spec;
3422 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
3423}
3424
3425/*
3426 * Digital out
3427 */
3428static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
3429 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003430 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431{
3432 struct alc_spec *spec = codec->spec;
3433 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
3434}
3435
Takashi Iwai6b97eb42007-04-05 14:51:48 +02003436static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
3437 struct hda_codec *codec,
3438 unsigned int stream_tag,
3439 unsigned int format,
3440 struct snd_pcm_substream *substream)
3441{
3442 struct alc_spec *spec = codec->spec;
3443 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
3444 stream_tag, format, substream);
3445}
3446
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01003447static int alc880_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3448 struct hda_codec *codec,
3449 struct snd_pcm_substream *substream)
3450{
3451 struct alc_spec *spec = codec->spec;
3452 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
3453}
3454
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
3456 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003457 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458{
3459 struct alc_spec *spec = codec->spec;
3460 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
3461}
3462
3463/*
3464 * Analog capture
3465 */
Takashi Iwai63300792008-01-24 15:31:36 +01003466static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467 struct hda_codec *codec,
3468 unsigned int stream_tag,
3469 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003470 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471{
3472 struct alc_spec *spec = codec->spec;
3473
Takashi Iwai63300792008-01-24 15:31:36 +01003474 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475 stream_tag, 0, format);
3476 return 0;
3477}
3478
Takashi Iwai63300792008-01-24 15:31:36 +01003479static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003481 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482{
3483 struct alc_spec *spec = codec->spec;
3484
Takashi Iwai888afa12008-03-18 09:57:50 +01003485 snd_hda_codec_cleanup_stream(codec,
3486 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 return 0;
3488}
3489
3490
3491/*
3492 */
3493static struct hda_pcm_stream alc880_pcm_analog_playback = {
3494 .substreams = 1,
3495 .channels_min = 2,
3496 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003497 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498 .ops = {
3499 .open = alc880_playback_pcm_open,
3500 .prepare = alc880_playback_pcm_prepare,
3501 .cleanup = alc880_playback_pcm_cleanup
3502 },
3503};
3504
3505static struct hda_pcm_stream alc880_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01003506 .substreams = 1,
3507 .channels_min = 2,
3508 .channels_max = 2,
3509 /* NID is set in alc_build_pcms */
3510};
3511
3512static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
3513 .substreams = 1,
3514 .channels_min = 2,
3515 .channels_max = 2,
3516 /* NID is set in alc_build_pcms */
3517};
3518
3519static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
3520 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 .channels_min = 2,
3522 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003523 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524 .ops = {
Takashi Iwai63300792008-01-24 15:31:36 +01003525 .prepare = alc880_alt_capture_pcm_prepare,
3526 .cleanup = alc880_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527 },
3528};
3529
3530static struct hda_pcm_stream alc880_pcm_digital_playback = {
3531 .substreams = 1,
3532 .channels_min = 2,
3533 .channels_max = 2,
3534 /* NID is set in alc_build_pcms */
3535 .ops = {
3536 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02003537 .close = alc880_dig_playback_pcm_close,
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01003538 .prepare = alc880_dig_playback_pcm_prepare,
3539 .cleanup = alc880_dig_playback_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540 },
3541};
3542
3543static struct hda_pcm_stream alc880_pcm_digital_capture = {
3544 .substreams = 1,
3545 .channels_min = 2,
3546 .channels_max = 2,
3547 /* NID is set in alc_build_pcms */
3548};
3549
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003550/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwai63300792008-01-24 15:31:36 +01003551static struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003552 .substreams = 0,
3553 .channels_min = 0,
3554 .channels_max = 0,
3555};
3556
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557static int alc_build_pcms(struct hda_codec *codec)
3558{
3559 struct alc_spec *spec = codec->spec;
3560 struct hda_pcm *info = spec->pcm_rec;
3561 int i;
3562
3563 codec->num_pcms = 1;
3564 codec->pcm_info = info;
3565
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003566 if (spec->no_analog)
3567 goto skip_analog;
3568
Takashi Iwai812a2cc2009-05-16 10:00:49 +02003569 snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog),
3570 "%s Analog", codec->chip_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571 info->name = spec->stream_name_analog;
Kailang Yang274693f2009-12-03 10:07:50 +01003572
Takashi Iwai4a471b72005-12-07 13:56:29 +01003573 if (spec->stream_analog_playback) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02003574 if (snd_BUG_ON(!spec->multiout.dac_nids))
3575 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003576 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
3577 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
3578 }
3579 if (spec->stream_analog_capture) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02003580 if (snd_BUG_ON(!spec->adc_nids))
3581 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003582 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
3583 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
3584 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585
Takashi Iwai4a471b72005-12-07 13:56:29 +01003586 if (spec->channel_mode) {
3587 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
3588 for (i = 0; i < spec->num_channel_mode; i++) {
3589 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
3590 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
3591 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592 }
3593 }
3594
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003595 skip_analog:
Takashi Iwaie08a0072006-09-07 17:52:14 +02003596 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwai812a2cc2009-05-16 10:00:49 +02003598 snprintf(spec->stream_name_digital,
3599 sizeof(spec->stream_name_digital),
3600 "%s Digital", codec->chip_name);
Takashi Iwaie08a0072006-09-07 17:52:14 +02003601 codec->num_pcms = 2;
Wu Fengguangb25c9da2009-02-06 15:02:27 +08003602 codec->slave_dig_outs = spec->multiout.slave_dig_outs;
Takashi Iwaic06134d2006-10-11 18:49:13 +02003603 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604 info->name = spec->stream_name_digital;
Takashi Iwai8c441982009-01-20 18:30:20 +01003605 if (spec->dig_out_type)
3606 info->pcm_type = spec->dig_out_type;
3607 else
3608 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003609 if (spec->multiout.dig_out_nid &&
3610 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
3612 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
3613 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01003614 if (spec->dig_in_nid &&
3615 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
3617 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
3618 }
Takashi Iwai963f8032008-08-11 10:04:40 +02003619 /* FIXME: do we need this for all Realtek codec models? */
3620 codec->spdif_status_reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621 }
3622
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003623 if (spec->no_analog)
3624 return 0;
3625
Takashi Iwaie08a0072006-09-07 17:52:14 +02003626 /* If the use of more than one ADC is requested for the current
3627 * model, configure a second analog capture-only PCM.
3628 */
3629 /* Additional Analaog capture for index #2 */
Takashi Iwai63300792008-01-24 15:31:36 +01003630 if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
3631 (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02003632 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02003633 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02003634 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01003635 if (spec->alt_dac_nid) {
3636 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
3637 *spec->stream_analog_alt_playback;
3638 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
3639 spec->alt_dac_nid;
3640 } else {
3641 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
3642 alc_pcm_null_stream;
3643 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
3644 }
3645 if (spec->num_adc_nids > 1) {
3646 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
3647 *spec->stream_analog_alt_capture;
3648 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
3649 spec->adc_nids[1];
3650 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
3651 spec->num_adc_nids - 1;
3652 } else {
3653 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
3654 alc_pcm_null_stream;
3655 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02003656 }
3657 }
3658
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659 return 0;
3660}
3661
Takashi Iwai603c4012008-07-30 15:01:44 +02003662static void alc_free_kctls(struct hda_codec *codec)
3663{
3664 struct alc_spec *spec = codec->spec;
3665
3666 if (spec->kctls.list) {
3667 struct snd_kcontrol_new *kctl = spec->kctls.list;
3668 int i;
3669 for (i = 0; i < spec->kctls.used; i++)
3670 kfree(kctl[i].name);
3671 }
3672 snd_array_free(&spec->kctls);
3673}
3674
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675static void alc_free(struct hda_codec *codec)
3676{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003677 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003678
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003679 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003680 return;
3681
Takashi Iwai603c4012008-07-30 15:01:44 +02003682 alc_free_kctls(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003683 kfree(spec);
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09003684 snd_hda_detach_beep_device(codec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685}
3686
Takashi Iwaie044c392008-10-27 16:56:24 +01003687#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaie044c392008-10-27 16:56:24 +01003688static int alc_resume(struct hda_codec *codec)
3689{
Takashi Iwaie044c392008-10-27 16:56:24 +01003690 codec->patch_ops.init(codec);
3691 snd_hda_codec_resume_amp(codec);
3692 snd_hda_codec_resume_cache(codec);
3693 return 0;
3694}
Takashi Iwaie044c392008-10-27 16:56:24 +01003695#endif
3696
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697/*
3698 */
3699static struct hda_codec_ops alc_patch_ops = {
3700 .build_controls = alc_build_controls,
3701 .build_pcms = alc_build_pcms,
3702 .init = alc_init,
3703 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003704 .unsol_event = alc_unsol_event,
Takashi Iwaie044c392008-10-27 16:56:24 +01003705#ifdef SND_HDA_NEEDS_RESUME
3706 .resume = alc_resume,
3707#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02003708#ifdef CONFIG_SND_HDA_POWER_SAVE
3709 .check_power_status = alc_check_power_status,
3710#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711};
3712
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003713
3714/*
3715 * Test configuration for debugging
3716 *
3717 * Almost all inputs/outputs are enabled. I/O pins can be configured via
3718 * enum controls.
3719 */
3720#ifdef CONFIG_SND_DEBUG
3721static hda_nid_t alc880_test_dac_nids[4] = {
3722 0x02, 0x03, 0x04, 0x05
3723};
3724
3725static struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003726 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003727 .items = {
3728 { "In-1", 0x0 },
3729 { "In-2", 0x1 },
3730 { "In-3", 0x2 },
3731 { "In-4", 0x3 },
3732 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003733 { "Front", 0x5 },
3734 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003735 },
3736};
3737
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01003738static struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003739 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02003740 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003741 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02003742 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003743};
3744
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003745static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
3746 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003747{
3748 static char *texts[] = {
3749 "N/A", "Line Out", "HP Out",
3750 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
3751 };
3752 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3753 uinfo->count = 1;
3754 uinfo->value.enumerated.items = 8;
3755 if (uinfo->value.enumerated.item >= 8)
3756 uinfo->value.enumerated.item = 7;
3757 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
3758 return 0;
3759}
3760
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003761static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
3762 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003763{
3764 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3765 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3766 unsigned int pin_ctl, item = 0;
3767
3768 pin_ctl = snd_hda_codec_read(codec, nid, 0,
3769 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3770 if (pin_ctl & AC_PINCTL_OUT_EN) {
3771 if (pin_ctl & AC_PINCTL_HP_EN)
3772 item = 2;
3773 else
3774 item = 1;
3775 } else if (pin_ctl & AC_PINCTL_IN_EN) {
3776 switch (pin_ctl & AC_PINCTL_VREFEN) {
3777 case AC_PINCTL_VREF_HIZ: item = 3; break;
3778 case AC_PINCTL_VREF_50: item = 4; break;
3779 case AC_PINCTL_VREF_GRD: item = 5; break;
3780 case AC_PINCTL_VREF_80: item = 6; break;
3781 case AC_PINCTL_VREF_100: item = 7; break;
3782 }
3783 }
3784 ucontrol->value.enumerated.item[0] = item;
3785 return 0;
3786}
3787
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003788static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
3789 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003790{
3791 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3792 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3793 static unsigned int ctls[] = {
3794 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
3795 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
3796 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
3797 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
3798 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
3799 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
3800 };
3801 unsigned int old_ctl, new_ctl;
3802
3803 old_ctl = snd_hda_codec_read(codec, nid, 0,
3804 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3805 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
3806 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003807 int val;
3808 snd_hda_codec_write_cache(codec, nid, 0,
3809 AC_VERB_SET_PIN_WIDGET_CONTROL,
3810 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02003811 val = ucontrol->value.enumerated.item[0] >= 3 ?
3812 HDA_AMP_MUTE : 0;
3813 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
3814 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003815 return 1;
3816 }
3817 return 0;
3818}
3819
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003820static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
3821 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003822{
3823 static char *texts[] = {
3824 "Front", "Surround", "CLFE", "Side"
3825 };
3826 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3827 uinfo->count = 1;
3828 uinfo->value.enumerated.items = 4;
3829 if (uinfo->value.enumerated.item >= 4)
3830 uinfo->value.enumerated.item = 3;
3831 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
3832 return 0;
3833}
3834
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003835static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
3836 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003837{
3838 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3839 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3840 unsigned int sel;
3841
3842 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
3843 ucontrol->value.enumerated.item[0] = sel & 3;
3844 return 0;
3845}
3846
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003847static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
3848 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003849{
3850 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3851 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3852 unsigned int sel;
3853
3854 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
3855 if (ucontrol->value.enumerated.item[0] != sel) {
3856 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003857 snd_hda_codec_write_cache(codec, nid, 0,
3858 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003859 return 1;
3860 }
3861 return 0;
3862}
3863
3864#define PIN_CTL_TEST(xname,nid) { \
3865 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3866 .name = xname, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003867 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003868 .info = alc_test_pin_ctl_info, \
3869 .get = alc_test_pin_ctl_get, \
3870 .put = alc_test_pin_ctl_put, \
3871 .private_value = nid \
3872 }
3873
3874#define PIN_SRC_TEST(xname,nid) { \
3875 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3876 .name = xname, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003877 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003878 .info = alc_test_pin_src_info, \
3879 .get = alc_test_pin_src_get, \
3880 .put = alc_test_pin_src_put, \
3881 .private_value = nid \
3882 }
3883
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003884static struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003885 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3886 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3887 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
3888 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003889 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
3890 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
3891 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
3892 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003893 PIN_CTL_TEST("Front Pin Mode", 0x14),
3894 PIN_CTL_TEST("Surround Pin Mode", 0x15),
3895 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
3896 PIN_CTL_TEST("Side Pin Mode", 0x17),
3897 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
3898 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
3899 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
3900 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
3901 PIN_SRC_TEST("In-1 Pin Source", 0x18),
3902 PIN_SRC_TEST("In-2 Pin Source", 0x19),
3903 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
3904 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
3905 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
3906 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
3907 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
3908 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
3909 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
3910 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
3911 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
3912 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
3913 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
3914 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003915 {
3916 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3917 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01003918 .info = alc_ch_mode_info,
3919 .get = alc_ch_mode_get,
3920 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003921 },
3922 { } /* end */
3923};
3924
3925static struct hda_verb alc880_test_init_verbs[] = {
3926 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02003927 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3928 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3929 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3930 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3931 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3932 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3933 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3934 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003935 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02003936 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3937 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3938 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3939 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003940 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003941 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3942 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3943 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3944 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003945 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003946 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3947 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3948 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3949 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003950 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02003951 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3952 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02003953 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3954 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3955 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003956 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02003957 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3958 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3959 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3960 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003961 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02003962 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003963 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003964 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003965 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003966 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003967 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003968 /* Analog input/passthru */
3969 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3970 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3971 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3972 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3973 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003974 { }
3975};
3976#endif
3977
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978/*
3979 */
3980
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003981static const char *alc880_models[ALC880_MODEL_LAST] = {
3982 [ALC880_3ST] = "3stack",
3983 [ALC880_TCL_S700] = "tcl",
3984 [ALC880_3ST_DIG] = "3stack-digout",
3985 [ALC880_CLEVO] = "clevo",
3986 [ALC880_5ST] = "5stack",
3987 [ALC880_5ST_DIG] = "5stack-digout",
3988 [ALC880_W810] = "w810",
3989 [ALC880_Z71V] = "z71v",
3990 [ALC880_6ST] = "6stack",
3991 [ALC880_6ST_DIG] = "6stack-digout",
3992 [ALC880_ASUS] = "asus",
3993 [ALC880_ASUS_W1V] = "asus-w1v",
3994 [ALC880_ASUS_DIG] = "asus-dig",
3995 [ALC880_ASUS_DIG2] = "asus-dig2",
3996 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003997 [ALC880_UNIWILL_P53] = "uniwill-p53",
3998 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003999 [ALC880_F1734] = "F1734",
4000 [ALC880_LG] = "lg",
4001 [ALC880_LG_LW] = "lg-lw",
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004002 [ALC880_MEDION_RIM] = "medion",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004003#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004004 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004005#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004006 [ALC880_AUTO] = "auto",
4007};
4008
4009static struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004010 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004011 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
4012 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
4013 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
4014 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
4015 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
4016 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
4017 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
4018 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004019 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
4020 SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004021 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
4022 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
4023 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
4024 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
4025 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
4026 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
4027 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
4028 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
4029 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
4030 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Travis Place186c3112008-05-20 11:54:41 +02004031 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004032 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
4033 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
4034 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004035 SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004036 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004037 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
4038 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004039 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
4040 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004041 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
4042 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
4043 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
4044 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004045 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
4046 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004047 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004048 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004049 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004050 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004051 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
4052 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004053 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004054 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004055 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004056 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004057 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Travis Place1d116042008-06-23 11:42:30 +02004058 SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004059 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004060 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004061 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004062 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
4063 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004064 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004065 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
4066 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
4067 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
4068 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004069 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
4070 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004071 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004072 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004073 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
4074 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004075 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
4076 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
4077 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004078 /* default Intel */
4079 SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004080 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
4081 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004082 {}
4083};
4084
Takashi Iwai16ded522005-06-10 19:58:24 +02004085/*
Kailang Yangdf694da2005-12-05 19:42:22 +01004086 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02004087 */
Takashi Iwai16ded522005-06-10 19:58:24 +02004088static struct alc_config_preset alc880_presets[] = {
4089 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004090 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004091 .init_verbs = { alc880_volume_init_verbs,
4092 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004093 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02004094 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004095 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4096 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004097 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004098 .input_mux = &alc880_capture_source,
4099 },
4100 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004101 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004102 .init_verbs = { alc880_volume_init_verbs,
4103 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004104 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02004105 .dac_nids = alc880_dac_nids,
4106 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004107 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4108 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004109 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004110 .input_mux = &alc880_capture_source,
4111 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004112 [ALC880_TCL_S700] = {
4113 .mixers = { alc880_tcl_s700_mixer },
4114 .init_verbs = { alc880_volume_init_verbs,
4115 alc880_pin_tcl_S700_init_verbs,
4116 alc880_gpio2_init_verbs },
4117 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4118 .dac_nids = alc880_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004119 .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */
4120 .num_adc_nids = 1, /* single ADC */
Kailang Yangdf694da2005-12-05 19:42:22 +01004121 .hp_nid = 0x03,
4122 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4123 .channel_mode = alc880_2_jack_modes,
4124 .input_mux = &alc880_capture_source,
4125 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004126 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004127 .mixers = { alc880_three_stack_mixer,
4128 alc880_five_stack_mixer},
4129 .init_verbs = { alc880_volume_init_verbs,
4130 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004131 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4132 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004133 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
4134 .channel_mode = alc880_fivestack_modes,
4135 .input_mux = &alc880_capture_source,
4136 },
4137 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004138 .mixers = { alc880_three_stack_mixer,
4139 alc880_five_stack_mixer },
4140 .init_verbs = { alc880_volume_init_verbs,
4141 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004142 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4143 .dac_nids = alc880_dac_nids,
4144 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004145 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
4146 .channel_mode = alc880_fivestack_modes,
4147 .input_mux = &alc880_capture_source,
4148 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02004149 [ALC880_6ST] = {
4150 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004151 .init_verbs = { alc880_volume_init_verbs,
4152 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02004153 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
4154 .dac_nids = alc880_6st_dac_nids,
4155 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
4156 .channel_mode = alc880_sixstack_modes,
4157 .input_mux = &alc880_6stack_capture_source,
4158 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004159 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004160 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004161 .init_verbs = { alc880_volume_init_verbs,
4162 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004163 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
4164 .dac_nids = alc880_6st_dac_nids,
4165 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004166 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
4167 .channel_mode = alc880_sixstack_modes,
4168 .input_mux = &alc880_6stack_capture_source,
4169 },
4170 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004171 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004172 .init_verbs = { alc880_volume_init_verbs,
4173 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02004174 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004175 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
4176 .dac_nids = alc880_w810_dac_nids,
4177 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004178 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
4179 .channel_mode = alc880_w810_modes,
4180 .input_mux = &alc880_capture_source,
4181 },
4182 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004183 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004184 .init_verbs = { alc880_volume_init_verbs,
4185 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004186 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
4187 .dac_nids = alc880_z71v_dac_nids,
4188 .dig_out_nid = ALC880_DIGOUT_NID,
4189 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004190 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4191 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02004192 .input_mux = &alc880_capture_source,
4193 },
4194 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004195 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004196 .init_verbs = { alc880_volume_init_verbs,
4197 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004198 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
4199 .dac_nids = alc880_f1734_dac_nids,
4200 .hp_nid = 0x02,
4201 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4202 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01004203 .input_mux = &alc880_f1734_capture_source,
4204 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004205 .setup = alc880_uniwill_p53_setup,
4206 .init_hook = alc_automute_amp,
Takashi Iwai16ded522005-06-10 19:58:24 +02004207 },
4208 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004209 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004210 .init_verbs = { alc880_volume_init_verbs,
4211 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004212 alc880_gpio1_init_verbs },
4213 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4214 .dac_nids = alc880_asus_dac_nids,
4215 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4216 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004217 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004218 .input_mux = &alc880_capture_source,
4219 },
4220 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004221 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004222 .init_verbs = { alc880_volume_init_verbs,
4223 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004224 alc880_gpio1_init_verbs },
4225 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4226 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004227 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004228 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4229 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004230 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004231 .input_mux = &alc880_capture_source,
4232 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004233 [ALC880_ASUS_DIG2] = {
4234 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004235 .init_verbs = { alc880_volume_init_verbs,
4236 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01004237 alc880_gpio2_init_verbs }, /* use GPIO2 */
4238 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4239 .dac_nids = alc880_asus_dac_nids,
4240 .dig_out_nid = ALC880_DIGOUT_NID,
4241 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4242 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004243 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01004244 .input_mux = &alc880_capture_source,
4245 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004246 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004247 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004248 .init_verbs = { alc880_volume_init_verbs,
4249 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004250 alc880_gpio1_init_verbs },
4251 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4252 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004253 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004254 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4255 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004256 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004257 .input_mux = &alc880_capture_source,
4258 },
4259 [ALC880_UNIWILL_DIG] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004260 .mixers = { alc880_asus_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02004261 .init_verbs = { alc880_volume_init_verbs,
4262 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004263 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4264 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004265 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004266 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4267 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004268 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004269 .input_mux = &alc880_capture_source,
4270 },
Kailang Yangccc656c2006-10-17 12:32:26 +02004271 [ALC880_UNIWILL] = {
4272 .mixers = { alc880_uniwill_mixer },
4273 .init_verbs = { alc880_volume_init_verbs,
4274 alc880_uniwill_init_verbs },
4275 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4276 .dac_nids = alc880_asus_dac_nids,
4277 .dig_out_nid = ALC880_DIGOUT_NID,
4278 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4279 .channel_mode = alc880_threestack_modes,
4280 .need_dac_fix = 1,
4281 .input_mux = &alc880_capture_source,
4282 .unsol_event = alc880_uniwill_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004283 .setup = alc880_uniwill_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004284 .init_hook = alc880_uniwill_init_hook,
Kailang Yangccc656c2006-10-17 12:32:26 +02004285 },
4286 [ALC880_UNIWILL_P53] = {
4287 .mixers = { alc880_uniwill_p53_mixer },
4288 .init_verbs = { alc880_volume_init_verbs,
4289 alc880_uniwill_p53_init_verbs },
4290 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4291 .dac_nids = alc880_asus_dac_nids,
4292 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004293 .channel_mode = alc880_threestack_modes,
4294 .input_mux = &alc880_capture_source,
4295 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004296 .setup = alc880_uniwill_p53_setup,
4297 .init_hook = alc_automute_amp,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004298 },
4299 [ALC880_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004300 .mixers = { alc880_fujitsu_mixer },
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004301 .init_verbs = { alc880_volume_init_verbs,
4302 alc880_uniwill_p53_init_verbs,
4303 alc880_beep_init_verbs },
4304 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4305 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02004306 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004307 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4308 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02004309 .input_mux = &alc880_capture_source,
4310 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004311 .setup = alc880_uniwill_p53_setup,
4312 .init_hook = alc_automute_amp,
Kailang Yangccc656c2006-10-17 12:32:26 +02004313 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004314 [ALC880_CLEVO] = {
4315 .mixers = { alc880_three_stack_mixer },
4316 .init_verbs = { alc880_volume_init_verbs,
4317 alc880_pin_clevo_init_verbs },
4318 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4319 .dac_nids = alc880_dac_nids,
4320 .hp_nid = 0x03,
4321 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4322 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004323 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01004324 .input_mux = &alc880_capture_source,
4325 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004326 [ALC880_LG] = {
4327 .mixers = { alc880_lg_mixer },
4328 .init_verbs = { alc880_volume_init_verbs,
4329 alc880_lg_init_verbs },
4330 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
4331 .dac_nids = alc880_lg_dac_nids,
4332 .dig_out_nid = ALC880_DIGOUT_NID,
4333 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
4334 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004335 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004336 .input_mux = &alc880_lg_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004337 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004338 .setup = alc880_lg_setup,
4339 .init_hook = alc_automute_amp,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004340#ifdef CONFIG_SND_HDA_POWER_SAVE
4341 .loopbacks = alc880_lg_loopbacks,
4342#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004343 },
Takashi Iwaid6815182006-03-23 16:06:23 +01004344 [ALC880_LG_LW] = {
4345 .mixers = { alc880_lg_lw_mixer },
4346 .init_verbs = { alc880_volume_init_verbs,
4347 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004348 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01004349 .dac_nids = alc880_dac_nids,
4350 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004351 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
4352 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01004353 .input_mux = &alc880_lg_lw_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004354 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004355 .setup = alc880_lg_lw_setup,
4356 .init_hook = alc_automute_amp,
Takashi Iwaid6815182006-03-23 16:06:23 +01004357 },
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004358 [ALC880_MEDION_RIM] = {
4359 .mixers = { alc880_medion_rim_mixer },
4360 .init_verbs = { alc880_volume_init_verbs,
4361 alc880_medion_rim_init_verbs,
4362 alc_gpio2_init_verbs },
4363 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4364 .dac_nids = alc880_dac_nids,
4365 .dig_out_nid = ALC880_DIGOUT_NID,
4366 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4367 .channel_mode = alc880_2_jack_modes,
4368 .input_mux = &alc880_medion_rim_capture_source,
4369 .unsol_event = alc880_medion_rim_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004370 .setup = alc880_medion_rim_setup,
4371 .init_hook = alc880_medion_rim_automute,
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004372 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004373#ifdef CONFIG_SND_DEBUG
4374 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004375 .mixers = { alc880_test_mixer },
4376 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004377 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
4378 .dac_nids = alc880_test_dac_nids,
4379 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004380 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
4381 .channel_mode = alc880_test_modes,
4382 .input_mux = &alc880_test_capture_source,
4383 },
4384#endif
4385};
4386
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004387/*
4388 * Automatic parse of I/O pins from the BIOS configuration
4389 */
4390
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004391enum {
4392 ALC_CTL_WIDGET_VOL,
4393 ALC_CTL_WIDGET_MUTE,
4394 ALC_CTL_BIND_MUTE,
4395};
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004396static struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004397 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
4398 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01004399 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004400};
4401
4402/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004403static int add_control(struct alc_spec *spec, int type, const char *name,
4404 unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004405{
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004406 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004407
Takashi Iwai603c4012008-07-30 15:01:44 +02004408 snd_array_init(&spec->kctls, sizeof(*knew), 32);
4409 knew = snd_array_new(&spec->kctls);
4410 if (!knew)
4411 return -ENOMEM;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004412 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07004413 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004414 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004415 return -ENOMEM;
Jaroslav Kysela4d02d1b2009-11-12 10:15:48 +01004416 if (get_amp_nid_(val))
Takashi Iwai9c96fa52009-11-16 11:25:33 +01004417 knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004418 knew->private_value = val;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004419 return 0;
4420}
4421
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004422static int add_control_with_pfx(struct alc_spec *spec, int type,
4423 const char *pfx, const char *dir,
4424 const char *sfx, unsigned long val)
4425{
4426 char name[32];
4427 snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
4428 return add_control(spec, type, name, val);
4429}
4430
4431#define add_pb_vol_ctrl(spec, type, pfx, val) \
4432 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", val)
4433#define add_pb_sw_ctrl(spec, type, pfx, val) \
4434 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", val)
4435
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004436#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
4437#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
4438#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
4439#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004440#define alc880_idx_to_dac(nid) ((nid) + 0x02)
4441#define alc880_dac_to_idx(nid) ((nid) - 0x02)
4442#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
4443#define alc880_idx_to_selector(nid) ((nid) + 0x10)
4444#define ALC880_PIN_CD_NID 0x1c
4445
4446/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004447static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
4448 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004449{
4450 hda_nid_t nid;
4451 int assigned[4];
4452 int i, j;
4453
4454 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02004455 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004456
4457 /* check the pins hardwired to audio widget */
4458 for (i = 0; i < cfg->line_outs; i++) {
4459 nid = cfg->line_out_pins[i];
4460 if (alc880_is_fixed_pin(nid)) {
4461 int idx = alc880_fixed_pin_idx(nid);
Libin Yang5014f192005-11-23 15:48:36 +01004462 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004463 assigned[idx] = 1;
4464 }
4465 }
4466 /* left pins can be connect to any audio widget */
4467 for (i = 0; i < cfg->line_outs; i++) {
4468 nid = cfg->line_out_pins[i];
4469 if (alc880_is_fixed_pin(nid))
4470 continue;
4471 /* search for an empty channel */
4472 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004473 if (!assigned[j]) {
4474 spec->multiout.dac_nids[i] =
4475 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004476 assigned[j] = 1;
4477 break;
4478 }
4479 }
4480 }
4481 spec->multiout.num_dacs = cfg->line_outs;
4482 return 0;
4483}
4484
4485/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01004486static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
4487 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004488{
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004489 static const char *chname[4] = {
4490 "Front", "Surround", NULL /*CLFE*/, "Side"
4491 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004492 hda_nid_t nid;
4493 int i, err;
4494
4495 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004496 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004497 continue;
4498 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
4499 if (i == 2) {
4500 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004501 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
4502 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004503 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
4504 HDA_OUTPUT));
4505 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004506 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004507 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
4508 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004509 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
4510 HDA_OUTPUT));
4511 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004512 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004513 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
4514 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004515 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
4516 HDA_INPUT));
4517 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004518 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004519 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
4520 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004521 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
4522 HDA_INPUT));
4523 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004524 return err;
4525 } else {
Takashi Iwaicb162b62009-08-25 16:05:03 +02004526 const char *pfx;
4527 if (cfg->line_outs == 1 &&
4528 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
4529 pfx = "Speaker";
4530 else
4531 pfx = chname[i];
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004532 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004533 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
4534 HDA_OUTPUT));
4535 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004536 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004537 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004538 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
4539 HDA_INPUT));
4540 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004541 return err;
4542 }
4543 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004544 return 0;
4545}
4546
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004547/* add playback controls for speaker and HP outputs */
4548static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
4549 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004550{
4551 hda_nid_t nid;
4552 int err;
4553
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004554 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004555 return 0;
4556
4557 if (alc880_is_fixed_pin(pin)) {
4558 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01004559 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004560 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004561 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01004562 else
4563 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004564 /* control HP volume/switch on the output mixer amp */
4565 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004566 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004567 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
4568 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004569 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004570 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004571 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
4572 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004573 return err;
4574 } else if (alc880_is_multi_pin(pin)) {
4575 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004576 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004577 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004578 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
4579 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004580 return err;
4581 }
4582 return 0;
4583}
4584
4585/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004586static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
4587 const char *ctlname,
Kailang Yangdf694da2005-12-05 19:42:22 +01004588 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004589{
Kailang Yangdf694da2005-12-05 19:42:22 +01004590 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004591
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004592 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004593 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
4594 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004595 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004596 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004597 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
4598 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004599 return err;
4600 return 0;
4601}
4602
Takashi Iwai05f5f472009-08-25 13:10:18 +02004603static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004604{
Takashi Iwai05f5f472009-08-25 13:10:18 +02004605 unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
4606 return (pincap & AC_PINCAP_IN) != 0;
4607}
4608
4609/* create playback/capture controls for input pins */
4610static int alc_auto_create_input_ctls(struct hda_codec *codec,
4611 const struct auto_pin_cfg *cfg,
4612 hda_nid_t mixer,
4613 hda_nid_t cap1, hda_nid_t cap2)
4614{
4615 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02004616 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004617 int i, err, idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004618
4619 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai05f5f472009-08-25 13:10:18 +02004620 hda_nid_t pin;
4621
4622 pin = cfg->input_pins[i];
4623 if (!alc_is_input_pin(codec, pin))
4624 continue;
4625
4626 if (mixer) {
4627 idx = get_connection_index(codec, mixer, pin);
4628 if (idx >= 0) {
4629 err = new_analog_input(spec, pin,
4630 auto_pin_cfg_labels[i],
4631 idx, mixer);
4632 if (err < 0)
4633 return err;
4634 }
4635 }
4636
4637 if (!cap1)
4638 continue;
4639 idx = get_connection_index(codec, cap1, pin);
4640 if (idx < 0 && cap2)
4641 idx = get_connection_index(codec, cap2, pin);
4642 if (idx >= 0) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004643 imux->items[imux->num_items].label =
4644 auto_pin_cfg_labels[i];
Takashi Iwai05f5f472009-08-25 13:10:18 +02004645 imux->items[imux->num_items].index = idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004646 imux->num_items++;
4647 }
4648 }
4649 return 0;
4650}
4651
Takashi Iwai05f5f472009-08-25 13:10:18 +02004652static int alc880_auto_create_input_ctls(struct hda_codec *codec,
4653 const struct auto_pin_cfg *cfg)
4654{
4655 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x08, 0x09);
4656}
4657
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004658static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
4659 unsigned int pin_type)
4660{
4661 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4662 pin_type);
4663 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01004664 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
4665 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004666}
4667
Kailang Yangdf694da2005-12-05 19:42:22 +01004668static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
4669 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004670 int dac_idx)
4671{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004672 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004673 /* need the manual connection? */
4674 if (alc880_is_multi_pin(nid)) {
4675 struct alc_spec *spec = codec->spec;
4676 int idx = alc880_multi_pin_idx(nid);
4677 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
4678 AC_VERB_SET_CONNECT_SEL,
4679 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
4680 }
4681}
4682
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004683static int get_pin_type(int line_out_type)
4684{
4685 if (line_out_type == AUTO_PIN_HP_OUT)
4686 return PIN_HP;
4687 else
4688 return PIN_OUT;
4689}
4690
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004691static void alc880_auto_init_multi_out(struct hda_codec *codec)
4692{
4693 struct alc_spec *spec = codec->spec;
4694 int i;
Kailang Yangea1fb292008-08-26 12:58:38 +02004695
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004696 for (i = 0; i < spec->autocfg.line_outs; i++) {
4697 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004698 int pin_type = get_pin_type(spec->autocfg.line_out_type);
4699 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004700 }
4701}
4702
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004703static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004704{
4705 struct alc_spec *spec = codec->spec;
4706 hda_nid_t pin;
4707
Takashi Iwai82bc9552006-03-21 11:24:42 +01004708 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004709 if (pin) /* connect to front */
4710 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004711 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004712 if (pin) /* connect to front */
4713 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
4714}
4715
4716static void alc880_auto_init_analog_input(struct hda_codec *codec)
4717{
4718 struct alc_spec *spec = codec->spec;
4719 int i;
4720
4721 for (i = 0; i < AUTO_PIN_LAST; i++) {
4722 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai05f5f472009-08-25 13:10:18 +02004723 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +01004724 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +01004725 if (nid != ALC880_PIN_CD_NID &&
4726 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004727 snd_hda_codec_write(codec, nid, 0,
4728 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004729 AMP_OUT_MUTE);
4730 }
4731 }
4732}
4733
4734/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004735/* return 1 if successful, 0 if the proper config is not found,
4736 * or a negative error code
4737 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004738static int alc880_parse_auto_config(struct hda_codec *codec)
4739{
4740 struct alc_spec *spec = codec->spec;
Takashi Iwai6a05ac42009-02-13 11:19:09 +01004741 int i, err;
Kailang Yangdf694da2005-12-05 19:42:22 +01004742 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004743
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004744 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
4745 alc880_ignore);
4746 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004747 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004748 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004749 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01004750
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004751 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
4752 if (err < 0)
4753 return err;
4754 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
4755 if (err < 0)
4756 return err;
4757 err = alc880_auto_create_extra_out(spec,
4758 spec->autocfg.speaker_pins[0],
4759 "Speaker");
4760 if (err < 0)
4761 return err;
4762 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
4763 "Headphone");
4764 if (err < 0)
4765 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +02004766 err = alc880_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004767 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004768 return err;
4769
4770 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
4771
Takashi Iwai6a05ac42009-02-13 11:19:09 +01004772 /* check multiple SPDIF-out (for recent codecs) */
4773 for (i = 0; i < spec->autocfg.dig_outs; i++) {
4774 hda_nid_t dig_nid;
4775 err = snd_hda_get_connections(codec,
4776 spec->autocfg.dig_out_pins[i],
4777 &dig_nid, 1);
4778 if (err < 0)
4779 continue;
4780 if (!i)
4781 spec->multiout.dig_out_nid = dig_nid;
4782 else {
4783 spec->multiout.slave_dig_outs = spec->slave_dig_outs;
Roel Kluin71121d9f2009-11-10 20:11:55 +01004784 if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
Takashi Iwai6a05ac42009-02-13 11:19:09 +01004785 break;
Roel Kluin71121d9f2009-11-10 20:11:55 +01004786 spec->slave_dig_outs[i - 1] = dig_nid;
Takashi Iwai6a05ac42009-02-13 11:19:09 +01004787 }
4788 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004789 if (spec->autocfg.dig_in_pin)
4790 spec->dig_in_nid = ALC880_DIGIN_NID;
4791
Takashi Iwai603c4012008-07-30 15:01:44 +02004792 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01004793 add_mixer(spec, spec->kctls.list);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004794
Takashi Iwaid88897e2008-10-31 15:01:37 +01004795 add_verb(spec, alc880_volume_init_verbs);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004796
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004797 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02004798 spec->input_mux = &spec->private_imux[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004799
Takashi Iwai4a79ba32009-04-22 16:31:35 +02004800 alc_ssid_check(codec, 0x15, 0x1b, 0x14);
4801
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004802 return 1;
4803}
4804
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004805/* additional initialization for auto-configuration model */
4806static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004807{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004808 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004809 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004810 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004811 alc880_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004812 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02004813 alc_inithook(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004814}
4815
Takashi Iwaib59bdf32009-08-11 09:47:30 +02004816/* check the ADC/MUX contains all input pins; some ADC/MUX contains only
4817 * one of two digital mic pins, e.g. on ALC272
4818 */
4819static void fixup_automic_adc(struct hda_codec *codec)
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004820{
Takashi Iwaib59bdf32009-08-11 09:47:30 +02004821 struct alc_spec *spec = codec->spec;
4822 int i;
4823
4824 for (i = 0; i < spec->num_adc_nids; i++) {
4825 hda_nid_t cap = spec->capsrc_nids ?
4826 spec->capsrc_nids[i] : spec->adc_nids[i];
4827 int iidx, eidx;
4828
4829 iidx = get_connection_index(codec, cap, spec->int_mic.pin);
4830 if (iidx < 0)
4831 continue;
4832 eidx = get_connection_index(codec, cap, spec->ext_mic.pin);
4833 if (eidx < 0)
4834 continue;
4835 spec->int_mic.mux_idx = iidx;
4836 spec->ext_mic.mux_idx = eidx;
4837 if (spec->capsrc_nids)
4838 spec->capsrc_nids += i;
4839 spec->adc_nids += i;
4840 spec->num_adc_nids = 1;
4841 return;
4842 }
4843 snd_printd(KERN_INFO "hda_codec: %s: "
4844 "No ADC/MUX containing both 0x%x and 0x%x pins\n",
4845 codec->chip_name, spec->int_mic.pin, spec->ext_mic.pin);
4846 spec->auto_mic = 0; /* disable auto-mic to be sure */
4847}
4848
4849static void set_capture_mixer(struct hda_codec *codec)
4850{
4851 struct alc_spec *spec = codec->spec;
Takashi Iwaia23b6882009-03-23 15:21:36 +01004852 static struct snd_kcontrol_new *caps[2][3] = {
4853 { alc_capture_mixer_nosrc1,
4854 alc_capture_mixer_nosrc2,
4855 alc_capture_mixer_nosrc3 },
4856 { alc_capture_mixer1,
4857 alc_capture_mixer2,
4858 alc_capture_mixer3 },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004859 };
Takashi Iwaia23b6882009-03-23 15:21:36 +01004860 if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
4861 int mux;
Takashi Iwai2a22d3f2009-08-10 18:54:38 +02004862 if (spec->auto_mic) {
4863 mux = 0;
Takashi Iwaib59bdf32009-08-11 09:47:30 +02004864 fixup_automic_adc(codec);
Takashi Iwai2a22d3f2009-08-10 18:54:38 +02004865 } else if (spec->input_mux && spec->input_mux->num_items > 1)
Takashi Iwaia23b6882009-03-23 15:21:36 +01004866 mux = 1;
4867 else
4868 mux = 0;
4869 spec->cap_mixer = caps[mux][spec->num_adc_nids - 1];
4870 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004871}
4872
Takashi Iwai67d634c2009-11-16 15:35:59 +01004873#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004874#define set_beep_amp(spec, nid, idx, dir) \
4875 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
Takashi Iwai67d634c2009-11-16 15:35:59 +01004876#else
4877#define set_beep_amp(spec, nid, idx, dir) /* NOP */
4878#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004879
4880/*
4881 * OK, here we have finally the patch for ALC880
4882 */
4883
Linus Torvalds1da177e2005-04-16 15:20:36 -07004884static int patch_alc880(struct hda_codec *codec)
4885{
4886 struct alc_spec *spec;
4887 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01004888 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004889
Takashi Iwaie560d8d2005-09-09 14:21:46 +02004890 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004891 if (spec == NULL)
4892 return -ENOMEM;
4893
4894 codec->spec = spec;
4895
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004896 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
4897 alc880_models,
4898 alc880_cfg_tbl);
4899 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02004900 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
4901 codec->chip_name);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004902 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004903 }
4904
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004905 if (board_config == ALC880_AUTO) {
4906 /* automatic parse from the BIOS config */
4907 err = alc880_parse_auto_config(codec);
4908 if (err < 0) {
4909 alc_free(codec);
4910 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004911 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004912 printk(KERN_INFO
4913 "hda_codec: Cannot set up configuration "
4914 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004915 board_config = ALC880_3ST;
4916 }
4917 }
4918
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09004919 err = snd_hda_attach_beep_device(codec, 0x1);
4920 if (err < 0) {
4921 alc_free(codec);
4922 return err;
4923 }
4924
Kailang Yangdf694da2005-12-05 19:42:22 +01004925 if (board_config != ALC880_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02004926 setup_preset(codec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004927
Linus Torvalds1da177e2005-04-16 15:20:36 -07004928 spec->stream_analog_playback = &alc880_pcm_analog_playback;
4929 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01004930 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004931
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932 spec->stream_digital_playback = &alc880_pcm_digital_playback;
4933 spec->stream_digital_capture = &alc880_pcm_digital_capture;
4934
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004935 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004936 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01004937 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004938 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +02004939 wcap = get_wcaps_type(wcap);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004940 if (wcap != AC_WID_AUD_IN) {
4941 spec->adc_nids = alc880_adc_nids_alt;
4942 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004943 } else {
4944 spec->adc_nids = alc880_adc_nids;
4945 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004946 }
4947 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02004948 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004949 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004950
Takashi Iwai2134ea42008-01-10 16:53:55 +01004951 spec->vmaster_nid = 0x0c;
4952
Linus Torvalds1da177e2005-04-16 15:20:36 -07004953 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004954 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004955 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02004956#ifdef CONFIG_SND_HDA_POWER_SAVE
4957 if (!spec->loopback.amplist)
4958 spec->loopback.amplist = alc880_loopbacks;
4959#endif
Takashi Iwaidaead532008-11-28 12:55:36 +01004960 codec->proc_widget_hook = print_realtek_coef;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004961
4962 return 0;
4963}
4964
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004965
Linus Torvalds1da177e2005-04-16 15:20:36 -07004966/*
4967 * ALC260 support
4968 */
4969
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004970static hda_nid_t alc260_dac_nids[1] = {
4971 /* front */
4972 0x02,
4973};
4974
4975static hda_nid_t alc260_adc_nids[1] = {
4976 /* ADC0 */
4977 0x04,
4978};
4979
Kailang Yangdf694da2005-12-05 19:42:22 +01004980static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004981 /* ADC1 */
4982 0x05,
4983};
4984
Jonathan Woithed57fdac2006-02-28 11:38:35 +01004985/* NIDs used when simultaneous access to both ADCs makes sense. Note that
4986 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
4987 */
4988static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004989 /* ADC0, ADC1 */
4990 0x04, 0x05
4991};
4992
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004993#define ALC260_DIGOUT_NID 0x03
4994#define ALC260_DIGIN_NID 0x06
4995
4996static struct hda_input_mux alc260_capture_source = {
4997 .num_items = 4,
4998 .items = {
4999 { "Mic", 0x0 },
5000 { "Front Mic", 0x1 },
5001 { "Line", 0x2 },
5002 { "CD", 0x4 },
5003 },
5004};
5005
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01005006/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005007 * headphone jack and the internal CD lines since these are the only pins at
5008 * which audio can appear. For flexibility, also allow the option of
5009 * recording the mixer output on the second ADC (ADC0 doesn't have a
5010 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005011 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005012static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
5013 {
5014 .num_items = 3,
5015 .items = {
5016 { "Mic/Line", 0x0 },
5017 { "CD", 0x4 },
5018 { "Headphone", 0x2 },
5019 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005020 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005021 {
5022 .num_items = 4,
5023 .items = {
5024 { "Mic/Line", 0x0 },
5025 { "CD", 0x4 },
5026 { "Headphone", 0x2 },
5027 { "Mixer", 0x5 },
5028 },
5029 },
5030
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005031};
5032
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005033/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
5034 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005035 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005036static struct hda_input_mux alc260_acer_capture_sources[2] = {
5037 {
5038 .num_items = 4,
5039 .items = {
5040 { "Mic", 0x0 },
5041 { "Line", 0x2 },
5042 { "CD", 0x4 },
5043 { "Headphone", 0x5 },
5044 },
5045 },
5046 {
5047 .num_items = 5,
5048 .items = {
5049 { "Mic", 0x0 },
5050 { "Line", 0x2 },
5051 { "CD", 0x4 },
5052 { "Headphone", 0x6 },
5053 { "Mixer", 0x5 },
5054 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005055 },
5056};
Michael Schwingencc959482009-02-22 18:58:45 +01005057
5058/* Maxdata Favorit 100XS */
5059static struct hda_input_mux alc260_favorit100_capture_sources[2] = {
5060 {
5061 .num_items = 2,
5062 .items = {
5063 { "Line/Mic", 0x0 },
5064 { "CD", 0x4 },
5065 },
5066 },
5067 {
5068 .num_items = 3,
5069 .items = {
5070 { "Line/Mic", 0x0 },
5071 { "CD", 0x4 },
5072 { "Mixer", 0x5 },
5073 },
5074 },
5075};
5076
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077/*
5078 * This is just place-holder, so there's something for alc_build_pcms to look
5079 * at when it calculates the maximum number of channels. ALC260 has no mixer
5080 * element which allows changing the channel mode, so the verb list is
5081 * never used.
5082 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01005083static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005084 { 2, NULL },
5085};
5086
Kailang Yangdf694da2005-12-05 19:42:22 +01005087
5088/* Mixer combinations
5089 *
5090 * basic: base_output + input + pc_beep + capture
5091 * HP: base_output + input + capture_alt
5092 * HP_3013: hp_3013 + input + capture
5093 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005094 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01005095 */
5096
5097static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02005098 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005099 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01005100 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5101 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
5102 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5103 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5104 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005105};
Kailang Yangdf694da2005-12-05 19:42:22 +01005106
5107static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5109 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5110 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5111 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5112 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5113 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5114 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
5115 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005116 { } /* end */
5117};
5118
Takashi Iwaibec15c32008-01-28 18:16:30 +01005119/* update HP, line and mono out pins according to the master switch */
5120static void alc260_hp_master_update(struct hda_codec *codec,
5121 hda_nid_t hp, hda_nid_t line,
5122 hda_nid_t mono)
5123{
5124 struct alc_spec *spec = codec->spec;
5125 unsigned int val = spec->master_sw ? PIN_HP : 0;
5126 /* change HP and line-out pins */
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005127 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005128 val);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005129 snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005130 val);
5131 /* mono (speaker) depending on the HP jack sense */
5132 val = (val && !spec->jack_present) ? PIN_OUT : 0;
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005133 snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005134 val);
5135}
5136
5137static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
5138 struct snd_ctl_elem_value *ucontrol)
5139{
5140 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5141 struct alc_spec *spec = codec->spec;
5142 *ucontrol->value.integer.value = spec->master_sw;
5143 return 0;
5144}
5145
5146static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
5147 struct snd_ctl_elem_value *ucontrol)
5148{
5149 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5150 struct alc_spec *spec = codec->spec;
5151 int val = !!*ucontrol->value.integer.value;
5152 hda_nid_t hp, line, mono;
5153
5154 if (val == spec->master_sw)
5155 return 0;
5156 spec->master_sw = val;
5157 hp = (kcontrol->private_value >> 16) & 0xff;
5158 line = (kcontrol->private_value >> 8) & 0xff;
5159 mono = kcontrol->private_value & 0xff;
5160 alc260_hp_master_update(codec, hp, line, mono);
5161 return 1;
5162}
5163
5164static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
5165 {
5166 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5167 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01005168 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005169 .info = snd_ctl_boolean_mono_info,
5170 .get = alc260_hp_master_sw_get,
5171 .put = alc260_hp_master_sw_put,
5172 .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
5173 },
5174 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5175 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
5176 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5177 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
5178 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
5179 HDA_OUTPUT),
5180 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5181 { } /* end */
5182};
5183
5184static struct hda_verb alc260_hp_unsol_verbs[] = {
5185 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5186 {},
5187};
5188
5189static void alc260_hp_automute(struct hda_codec *codec)
5190{
5191 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01005192
Wu Fengguang864f92b2009-11-18 12:38:02 +08005193 spec->jack_present = snd_hda_jack_detect(codec, 0x10);
Takashi Iwaibec15c32008-01-28 18:16:30 +01005194 alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
5195}
5196
5197static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
5198{
5199 if ((res >> 26) == ALC880_HP_EVENT)
5200 alc260_hp_automute(codec);
5201}
5202
Kailang Yangdf694da2005-12-05 19:42:22 +01005203static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01005204 {
5205 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5206 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01005207 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005208 .info = snd_ctl_boolean_mono_info,
5209 .get = alc260_hp_master_sw_get,
5210 .put = alc260_hp_master_sw_put,
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005211 .private_value = (0x15 << 16) | (0x10 << 8) | 0x11
Takashi Iwaibec15c32008-01-28 18:16:30 +01005212 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005213 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5214 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
5215 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
5216 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
5217 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5218 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01005219 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5220 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02005221 { } /* end */
5222};
5223
Kailang Yang3f878302008-08-26 13:02:23 +02005224static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
5225 .ops = &snd_hda_bind_vol,
5226 .values = {
5227 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
5228 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
5229 HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
5230 0
5231 },
5232};
5233
5234static struct hda_bind_ctls alc260_dc7600_bind_switch = {
5235 .ops = &snd_hda_bind_sw,
5236 .values = {
5237 HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
5238 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
5239 0
5240 },
5241};
5242
5243static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
5244 HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
5245 HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
5246 HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
5247 HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
5248 { } /* end */
5249};
5250
Takashi Iwaibec15c32008-01-28 18:16:30 +01005251static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
5252 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5253 {},
5254};
5255
5256static void alc260_hp_3013_automute(struct hda_codec *codec)
5257{
5258 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01005259
Wu Fengguang864f92b2009-11-18 12:38:02 +08005260 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005261 alc260_hp_master_update(codec, 0x15, 0x10, 0x11);
Takashi Iwaibec15c32008-01-28 18:16:30 +01005262}
5263
5264static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
5265 unsigned int res)
5266{
5267 if ((res >> 26) == ALC880_HP_EVENT)
5268 alc260_hp_3013_automute(codec);
5269}
5270
Kailang Yang3f878302008-08-26 13:02:23 +02005271static void alc260_hp_3012_automute(struct hda_codec *codec)
5272{
Wu Fengguang864f92b2009-11-18 12:38:02 +08005273 unsigned int bits = snd_hda_jack_detect(codec, 0x10) ? 0 : PIN_OUT;
Kailang Yang3f878302008-08-26 13:02:23 +02005274
Kailang Yang3f878302008-08-26 13:02:23 +02005275 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5276 bits);
5277 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5278 bits);
5279 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5280 bits);
5281}
5282
5283static void alc260_hp_3012_unsol_event(struct hda_codec *codec,
5284 unsigned int res)
5285{
5286 if ((res >> 26) == ALC880_HP_EVENT)
5287 alc260_hp_3012_automute(codec);
5288}
5289
5290/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005291 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
5292 */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01005293static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005294 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005295 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005296 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005297 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5298 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5299 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
5300 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005301 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01005302 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5303 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01005304 { } /* end */
5305};
5306
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005307/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
5308 * versions of the ALC260 don't act on requests to enable mic bias from NID
5309 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
5310 * datasheet doesn't mention this restriction. At this stage it's not clear
5311 * whether this behaviour is intentional or is a hardware bug in chip
5312 * revisions available in early 2006. Therefore for now allow the
5313 * "Headphone Jack Mode" control to span all choices, but if it turns out
5314 * that the lack of mic bias for this NID is intentional we could change the
5315 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
5316 *
5317 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
5318 * don't appear to make the mic bias available from the "line" jack, even
5319 * though the NID used for this jack (0x14) can supply it. The theory is
5320 * that perhaps Acer have included blocking capacitors between the ALC260
5321 * and the output jack. If this turns out to be the case for all such
5322 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
5323 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01005324 *
5325 * The C20x Tablet series have a mono internal speaker which is controlled
5326 * via the chip's Mono sum widget and pin complex, so include the necessary
5327 * controls for such models. On models without a "mono speaker" the control
5328 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005329 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005330static struct snd_kcontrol_new alc260_acer_mixer[] = {
5331 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5332 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005333 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01005334 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01005335 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01005336 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01005337 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005338 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5339 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5340 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5341 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5342 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5343 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5344 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5345 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005346 { } /* end */
5347};
5348
Michael Schwingencc959482009-02-22 18:58:45 +01005349/* Maxdata Favorit 100XS: one output and one input (0x12) jack
5350 */
5351static struct snd_kcontrol_new alc260_favorit100_mixer[] = {
5352 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5353 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
5354 ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
5355 HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5356 HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5357 ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5358 { } /* end */
5359};
5360
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005361/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
5362 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
5363 */
5364static struct snd_kcontrol_new alc260_will_mixer[] = {
5365 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5366 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
5367 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5368 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5369 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5370 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5371 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5372 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
5373 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5374 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005375 { } /* end */
5376};
5377
5378/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
5379 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
5380 */
5381static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
5382 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5383 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
5384 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5385 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5386 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5387 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
5388 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
5389 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5390 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5391 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
5392 { } /* end */
5393};
5394
Kailang Yangdf694da2005-12-05 19:42:22 +01005395/*
5396 * initialization verbs
5397 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398static struct hda_verb alc260_init_verbs[] = {
5399 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005400 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005401 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005402 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005403 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005404 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005405 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005406 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02005408 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01005410 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005411 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02005412 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005413 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02005414 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005415 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02005416 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5417 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02005418 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005419 /* set connection select to line in (default select for this ADC) */
5420 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02005421 /* mute capture amp left and right */
5422 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5423 /* set connection select to line in (default select for this ADC) */
5424 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02005425 /* set vol=0 Line-Out mixer amp left and right */
5426 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5427 /* unmute pin widget amp left and right (no gain on this amp) */
5428 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5429 /* set vol=0 HP mixer amp left and right */
5430 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5431 /* unmute pin widget amp left and right (no gain on this amp) */
5432 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5433 /* set vol=0 Mono mixer amp left and right */
5434 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5435 /* unmute pin widget amp left and right (no gain on this amp) */
5436 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5437 /* unmute LINE-2 out pin */
5438 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005439 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
5440 * Line In 2 = 0x03
5441 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005442 /* mute analog inputs */
5443 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5444 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5445 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5446 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5447 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005448 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005449 /* mute Front out path */
5450 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5451 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5452 /* mute Headphone out path */
5453 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5454 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5455 /* mute Mono out path */
5456 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5457 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005458 { }
5459};
5460
Takashi Iwai474167d2006-05-17 17:17:43 +02005461#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01005462static struct hda_verb alc260_hp_init_verbs[] = {
5463 /* Headphone and output */
5464 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
5465 /* mono output */
5466 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5467 /* Mic1 (rear panel) pin widget for input and vref at 80% */
5468 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5469 /* Mic2 (front panel) pin widget for input and vref at 80% */
5470 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5471 /* Line In pin widget for input */
5472 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5473 /* Line-2 pin widget for output */
5474 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5475 /* CD pin widget for input */
5476 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5477 /* unmute amp left and right */
5478 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
5479 /* set connection select to line in (default select for this ADC) */
5480 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
5481 /* unmute Line-Out mixer amp left and right (volume = 0) */
5482 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5483 /* mute pin widget amp left and right (no gain on this amp) */
5484 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
5485 /* unmute HP mixer amp left and right (volume = 0) */
5486 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5487 /* mute pin widget amp left and right (no gain on this amp) */
5488 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005489 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
5490 * Line In 2 = 0x03
5491 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005492 /* mute analog inputs */
5493 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5494 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5495 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5496 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5497 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005498 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
5499 /* Unmute Front out path */
5500 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5501 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5502 /* Unmute Headphone out path */
5503 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5504 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5505 /* Unmute Mono out path */
5506 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5507 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5508 { }
5509};
Takashi Iwai474167d2006-05-17 17:17:43 +02005510#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01005511
5512static struct hda_verb alc260_hp_3013_init_verbs[] = {
5513 /* Line out and output */
5514 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5515 /* mono output */
5516 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5517 /* Mic1 (rear panel) pin widget for input and vref at 80% */
5518 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5519 /* Mic2 (front panel) pin widget for input and vref at 80% */
5520 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5521 /* Line In pin widget for input */
5522 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5523 /* Headphone pin widget for output */
5524 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
5525 /* CD pin widget for input */
5526 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5527 /* unmute amp left and right */
5528 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
5529 /* set connection select to line in (default select for this ADC) */
5530 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
5531 /* unmute Line-Out mixer amp left and right (volume = 0) */
5532 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5533 /* mute pin widget amp left and right (no gain on this amp) */
5534 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
5535 /* unmute HP mixer amp left and right (volume = 0) */
5536 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5537 /* mute pin widget amp left and right (no gain on this amp) */
5538 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005539 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
5540 * Line In 2 = 0x03
5541 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005542 /* mute analog inputs */
5543 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5544 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5545 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5546 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5547 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005548 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
5549 /* Unmute Front out path */
5550 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5551 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5552 /* Unmute Headphone out path */
5553 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5554 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5555 /* Unmute Mono out path */
5556 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5557 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5558 { }
5559};
5560
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005561/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005562 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
5563 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005564 */
5565static struct hda_verb alc260_fujitsu_init_verbs[] = {
5566 /* Disable all GPIOs */
5567 {0x01, AC_VERB_SET_GPIO_MASK, 0},
5568 /* Internal speaker is connected to headphone pin */
5569 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5570 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
5571 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005572 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
5573 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
5574 /* Ensure all other unused pins are disabled and muted. */
5575 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5576 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005577 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005578 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005579 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005580 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5581 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5582 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005583
Jonathan Woithef7ace402006-02-28 11:46:14 +01005584 /* Disable digital (SPDIF) pins */
5585 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5586 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005587
Kailang Yangea1fb292008-08-26 12:58:38 +02005588 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
Jonathan Woithef7ace402006-02-28 11:46:14 +01005589 * when acting as an output.
5590 */
5591 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5592
5593 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01005594 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5595 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5596 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5597 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5598 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5599 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5600 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5601 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5602 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005603
Jonathan Woithef7ace402006-02-28 11:46:14 +01005604 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
5605 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5606 /* Unmute Line1 pin widget output buffer since it starts as an output.
5607 * If the pin mode is changed by the user the pin mode control will
5608 * take care of enabling the pin's input/output buffers as needed.
5609 * Therefore there's no need to enable the input buffer at this
5610 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01005611 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01005612 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +02005613 /* Unmute input buffer of pin widget used for Line-in (no equiv
Jonathan Woithecdcd9262006-02-28 11:36:42 +01005614 * mixer ctrl)
5615 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01005616 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005617
Jonathan Woithef7ace402006-02-28 11:46:14 +01005618 /* Mute capture amp left and right */
5619 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02005620 /* Set ADC connection select to match default mixer setting - line
Jonathan Woithef7ace402006-02-28 11:46:14 +01005621 * in (on mic1 pin)
5622 */
5623 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005624
Jonathan Woithef7ace402006-02-28 11:46:14 +01005625 /* Do the same for the second ADC: mute capture input amp and
5626 * set ADC connection to line in (on mic1 pin)
5627 */
5628 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5629 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005630
Jonathan Woithef7ace402006-02-28 11:46:14 +01005631 /* Mute all inputs to mixer widget (even unconnected ones) */
5632 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5633 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5634 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5635 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5636 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5637 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5638 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5639 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01005640
5641 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005642};
5643
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005644/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
5645 * similar laptops (adapted from Fujitsu init verbs).
5646 */
5647static struct hda_verb alc260_acer_init_verbs[] = {
5648 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
5649 * the headphone jack. Turn this on and rely on the standard mute
5650 * methods whenever the user wants to turn these outputs off.
5651 */
5652 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
5653 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
5654 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
5655 /* Internal speaker/Headphone jack is connected to Line-out pin */
5656 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5657 /* Internal microphone/Mic jack is connected to Mic1 pin */
5658 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
5659 /* Line In jack is connected to Line1 pin */
5660 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01005661 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
5662 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005663 /* Ensure all other unused pins are disabled and muted. */
5664 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5665 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005666 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5667 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5668 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5669 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5670 /* Disable digital (SPDIF) pins */
5671 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5672 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
5673
Kailang Yangea1fb292008-08-26 12:58:38 +02005674 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005675 * bus when acting as outputs.
5676 */
5677 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
5678 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5679
5680 /* Start with output sum widgets muted and their output gains at min */
5681 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5682 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5683 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5684 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5685 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5686 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5687 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5688 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5689 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5690
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005691 /* Unmute Line-out pin widget amp left and right
5692 * (no equiv mixer ctrl)
5693 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005694 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01005695 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
5696 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005697 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
5698 * inputs. If the pin mode is changed by the user the pin mode control
5699 * will take care of enabling the pin's input/output buffers as needed.
5700 * Therefore there's no need to enable the input buffer at this
5701 * stage.
5702 */
5703 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5704 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5705
5706 /* Mute capture amp left and right */
5707 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5708 /* Set ADC connection select to match default mixer setting - mic
5709 * (on mic1 pin)
5710 */
5711 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5712
5713 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005714 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005715 */
5716 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005717 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005718
5719 /* Mute all inputs to mixer widget (even unconnected ones) */
5720 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5721 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5722 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5723 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5724 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5725 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5726 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5727 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
5728
5729 { }
5730};
5731
Michael Schwingencc959482009-02-22 18:58:45 +01005732/* Initialisation sequence for Maxdata Favorit 100XS
5733 * (adapted from Acer init verbs).
5734 */
5735static struct hda_verb alc260_favorit100_init_verbs[] = {
5736 /* GPIO 0 enables the output jack.
5737 * Turn this on and rely on the standard mute
5738 * methods whenever the user wants to turn these outputs off.
5739 */
5740 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
5741 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
5742 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
5743 /* Line/Mic input jack is connected to Mic1 pin */
5744 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
5745 /* Ensure all other unused pins are disabled and muted. */
5746 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5747 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5748 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5749 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5750 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5751 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5752 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5753 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5754 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5755 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5756 /* Disable digital (SPDIF) pins */
5757 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5758 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
5759
5760 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
5761 * bus when acting as outputs.
5762 */
5763 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
5764 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5765
5766 /* Start with output sum widgets muted and their output gains at min */
5767 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5768 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5769 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5770 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5771 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5772 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5773 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5774 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5775 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5776
5777 /* Unmute Line-out pin widget amp left and right
5778 * (no equiv mixer ctrl)
5779 */
5780 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5781 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
5782 * inputs. If the pin mode is changed by the user the pin mode control
5783 * will take care of enabling the pin's input/output buffers as needed.
5784 * Therefore there's no need to enable the input buffer at this
5785 * stage.
5786 */
5787 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5788
5789 /* Mute capture amp left and right */
5790 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5791 /* Set ADC connection select to match default mixer setting - mic
5792 * (on mic1 pin)
5793 */
5794 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5795
5796 /* Do similar with the second ADC: mute capture input amp and
5797 * set ADC connection to mic to match ALSA's default state.
5798 */
5799 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5800 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
5801
5802 /* Mute all inputs to mixer widget (even unconnected ones) */
5803 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5804 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5805 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5806 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5807 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5808 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5809 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5810 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
5811
5812 { }
5813};
5814
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005815static struct hda_verb alc260_will_verbs[] = {
5816 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5817 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
5818 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
5819 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
5820 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
5821 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
5822 {}
5823};
5824
5825static struct hda_verb alc260_replacer_672v_verbs[] = {
5826 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
5827 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
5828 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
5829
5830 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
5831 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
5832 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
5833
5834 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5835 {}
5836};
5837
5838/* toggle speaker-output according to the hp-jack state */
5839static void alc260_replacer_672v_automute(struct hda_codec *codec)
5840{
5841 unsigned int present;
5842
5843 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
Wu Fengguang864f92b2009-11-18 12:38:02 +08005844 present = snd_hda_jack_detect(codec, 0x0f);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005845 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005846 snd_hda_codec_write_cache(codec, 0x01, 0,
5847 AC_VERB_SET_GPIO_DATA, 1);
5848 snd_hda_codec_write_cache(codec, 0x0f, 0,
5849 AC_VERB_SET_PIN_WIDGET_CONTROL,
5850 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005851 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005852 snd_hda_codec_write_cache(codec, 0x01, 0,
5853 AC_VERB_SET_GPIO_DATA, 0);
5854 snd_hda_codec_write_cache(codec, 0x0f, 0,
5855 AC_VERB_SET_PIN_WIDGET_CONTROL,
5856 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005857 }
5858}
5859
5860static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
5861 unsigned int res)
5862{
5863 if ((res >> 26) == ALC880_HP_EVENT)
5864 alc260_replacer_672v_automute(codec);
5865}
5866
Kailang Yang3f878302008-08-26 13:02:23 +02005867static struct hda_verb alc260_hp_dc7600_verbs[] = {
5868 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
5869 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
5870 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5871 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5872 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5873 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5874 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5875 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5876 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5877 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5878 {}
5879};
5880
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005881/* Test configuration for debugging, modelled after the ALC880 test
5882 * configuration.
5883 */
5884#ifdef CONFIG_SND_DEBUG
5885static hda_nid_t alc260_test_dac_nids[1] = {
5886 0x02,
5887};
5888static hda_nid_t alc260_test_adc_nids[2] = {
5889 0x04, 0x05,
5890};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005891/* For testing the ALC260, each input MUX needs its own definition since
Kailang Yangea1fb292008-08-26 12:58:38 +02005892 * the signal assignments are different. This assumes that the first ADC
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005893 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01005894 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005895static struct hda_input_mux alc260_test_capture_sources[2] = {
5896 {
5897 .num_items = 7,
5898 .items = {
5899 { "MIC1 pin", 0x0 },
5900 { "MIC2 pin", 0x1 },
5901 { "LINE1 pin", 0x2 },
5902 { "LINE2 pin", 0x3 },
5903 { "CD pin", 0x4 },
5904 { "LINE-OUT pin", 0x5 },
5905 { "HP-OUT pin", 0x6 },
5906 },
5907 },
5908 {
5909 .num_items = 8,
5910 .items = {
5911 { "MIC1 pin", 0x0 },
5912 { "MIC2 pin", 0x1 },
5913 { "LINE1 pin", 0x2 },
5914 { "LINE2 pin", 0x3 },
5915 { "CD pin", 0x4 },
5916 { "Mixer", 0x5 },
5917 { "LINE-OUT pin", 0x6 },
5918 { "HP-OUT pin", 0x7 },
5919 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005920 },
5921};
5922static struct snd_kcontrol_new alc260_test_mixer[] = {
5923 /* Output driver widgets */
5924 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5925 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5926 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5927 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
5928 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5929 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
5930
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005931 /* Modes for retasking pin widgets
5932 * Note: the ALC260 doesn't seem to act on requests to enable mic
5933 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
5934 * mention this restriction. At this stage it's not clear whether
5935 * this behaviour is intentional or is a hardware bug in chip
5936 * revisions available at least up until early 2006. Therefore for
5937 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
5938 * choices, but if it turns out that the lack of mic bias for these
5939 * NIDs is intentional we could change their modes from
5940 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
5941 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005942 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
5943 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
5944 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
5945 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
5946 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
5947 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
5948
5949 /* Loopback mixer controls */
5950 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
5951 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
5952 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
5953 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
5954 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
5955 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
5956 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
5957 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
5958 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5959 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005960 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
5961 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
5962 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
5963 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01005964
5965 /* Controls for GPIO pins, assuming they are configured as outputs */
5966 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
5967 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
5968 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
5969 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
5970
Jonathan Woithe92621f12006-02-28 11:47:47 +01005971 /* Switches to allow the digital IO pins to be enabled. The datasheet
5972 * is ambigious as to which NID is which; testing on laptops which
Kailang Yangea1fb292008-08-26 12:58:38 +02005973 * make this output available should provide clarification.
Jonathan Woithe92621f12006-02-28 11:47:47 +01005974 */
5975 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
5976 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
5977
Jonathan Woithef8225f62008-01-08 12:16:54 +01005978 /* A switch allowing EAPD to be enabled. Some laptops seem to use
5979 * this output to turn on an external amplifier.
5980 */
5981 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
5982 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
5983
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005984 { } /* end */
5985};
5986static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01005987 /* Enable all GPIOs as outputs with an initial value of 0 */
5988 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
5989 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
5990 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
5991
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005992 /* Enable retasking pins as output, initially without power amp */
5993 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5994 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5995 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5996 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5997 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5998 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5999
Jonathan Woithe92621f12006-02-28 11:47:47 +01006000 /* Disable digital (SPDIF) pins initially, but users can enable
6001 * them via a mixer switch. In the case of SPDIF-out, this initverb
6002 * payload also sets the generation to 0, output to be in "consumer"
6003 * PCM format, copyright asserted, no pre-emphasis and no validity
6004 * control.
6005 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006006 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6007 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6008
Kailang Yangea1fb292008-08-26 12:58:38 +02006009 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006010 * OUT1 sum bus when acting as an output.
6011 */
6012 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6013 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
6014 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6015 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
6016
6017 /* Start with output sum widgets muted and their output gains at min */
6018 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6019 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6020 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6021 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6022 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6023 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6024 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6025 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6026 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6027
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006028 /* Unmute retasking pin widget output buffers since the default
6029 * state appears to be output. As the pin mode is changed by the
6030 * user the pin mode control will take care of enabling the pin's
6031 * input/output buffers as needed.
6032 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006033 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6034 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6035 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6036 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6037 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6038 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6039 /* Also unmute the mono-out pin widget */
6040 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6041
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006042 /* Mute capture amp left and right */
6043 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006044 /* Set ADC connection select to match default mixer setting (mic1
6045 * pin)
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006046 */
6047 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6048
6049 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01006050 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006051 */
6052 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6053 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6054
6055 /* Mute all inputs to mixer widget (even unconnected ones) */
6056 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6057 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6058 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6059 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6060 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6061 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6062 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6063 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6064
6065 { }
6066};
6067#endif
6068
Takashi Iwai63300792008-01-24 15:31:36 +01006069#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
6070#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07006071
Takashi Iwaia3bcba32005-12-06 19:05:29 +01006072#define alc260_pcm_digital_playback alc880_pcm_digital_playback
6073#define alc260_pcm_digital_capture alc880_pcm_digital_capture
6074
Kailang Yangdf694da2005-12-05 19:42:22 +01006075/*
6076 * for BIOS auto-configuration
6077 */
6078
6079static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai863b4512008-10-21 17:01:47 +02006080 const char *pfx, int *vol_bits)
Kailang Yangdf694da2005-12-05 19:42:22 +01006081{
6082 hda_nid_t nid_vol;
6083 unsigned long vol_val, sw_val;
Kailang Yangdf694da2005-12-05 19:42:22 +01006084 int err;
6085
6086 if (nid >= 0x0f && nid < 0x11) {
6087 nid_vol = nid - 0x7;
6088 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
6089 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
6090 } else if (nid == 0x11) {
6091 nid_vol = nid - 0x7;
6092 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
6093 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
6094 } else if (nid >= 0x12 && nid <= 0x15) {
6095 nid_vol = 0x08;
6096 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
6097 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
6098 } else
6099 return 0; /* N/A */
Kailang Yangea1fb292008-08-26 12:58:38 +02006100
Takashi Iwai863b4512008-10-21 17:01:47 +02006101 if (!(*vol_bits & (1 << nid_vol))) {
6102 /* first control for the volume widget */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02006103 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, vol_val);
Takashi Iwai863b4512008-10-21 17:01:47 +02006104 if (err < 0)
6105 return err;
6106 *vol_bits |= (1 << nid_vol);
6107 }
Takashi Iwai0afe5f82009-10-02 09:20:00 +02006108 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, sw_val);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006109 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006110 return err;
6111 return 1;
6112}
6113
6114/* add playback controls from the parsed DAC table */
6115static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
6116 const struct auto_pin_cfg *cfg)
6117{
6118 hda_nid_t nid;
6119 int err;
Takashi Iwai863b4512008-10-21 17:01:47 +02006120 int vols = 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01006121
6122 spec->multiout.num_dacs = 1;
6123 spec->multiout.dac_nids = spec->private_dac_nids;
6124 spec->multiout.dac_nids[0] = 0x02;
6125
6126 nid = cfg->line_out_pins[0];
6127 if (nid) {
Takashi Iwai23112d62009-08-25 16:07:08 +02006128 const char *pfx;
6129 if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
6130 pfx = "Master";
6131 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
6132 pfx = "Speaker";
6133 else
6134 pfx = "Front";
6135 err = alc260_add_playback_controls(spec, nid, pfx, &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006136 if (err < 0)
6137 return err;
6138 }
6139
Takashi Iwai82bc9552006-03-21 11:24:42 +01006140 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006141 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02006142 err = alc260_add_playback_controls(spec, nid, "Speaker", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006143 if (err < 0)
6144 return err;
6145 }
6146
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006147 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006148 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02006149 err = alc260_add_playback_controls(spec, nid, "Headphone",
6150 &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006151 if (err < 0)
6152 return err;
6153 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006154 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01006155}
6156
6157/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +02006158static int alc260_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yangdf694da2005-12-05 19:42:22 +01006159 const struct auto_pin_cfg *cfg)
6160{
Takashi Iwai05f5f472009-08-25 13:10:18 +02006161 return alc_auto_create_input_ctls(codec, cfg, 0x07, 0x04, 0x05);
Kailang Yangdf694da2005-12-05 19:42:22 +01006162}
6163
6164static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
6165 hda_nid_t nid, int pin_type,
6166 int sel_idx)
6167{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006168 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006169 /* need the manual connection? */
6170 if (nid >= 0x12) {
6171 int idx = nid - 0x12;
6172 snd_hda_codec_write(codec, idx + 0x0b, 0,
6173 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01006174 }
6175}
6176
6177static void alc260_auto_init_multi_out(struct hda_codec *codec)
6178{
6179 struct alc_spec *spec = codec->spec;
6180 hda_nid_t nid;
6181
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006182 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006183 if (nid) {
6184 int pin_type = get_pin_type(spec->autocfg.line_out_type);
6185 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
6186 }
Kailang Yangea1fb292008-08-26 12:58:38 +02006187
Takashi Iwai82bc9552006-03-21 11:24:42 +01006188 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006189 if (nid)
6190 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
6191
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006192 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006193 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006194 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006195}
Kailang Yangdf694da2005-12-05 19:42:22 +01006196
6197#define ALC260_PIN_CD_NID 0x16
6198static void alc260_auto_init_analog_input(struct hda_codec *codec)
6199{
6200 struct alc_spec *spec = codec->spec;
6201 int i;
6202
6203 for (i = 0; i < AUTO_PIN_LAST; i++) {
6204 hda_nid_t nid = spec->autocfg.input_pins[i];
6205 if (nid >= 0x12) {
Takashi Iwai23f0c042009-02-26 13:03:58 +01006206 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +01006207 if (nid != ALC260_PIN_CD_NID &&
6208 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006209 snd_hda_codec_write(codec, nid, 0,
6210 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01006211 AMP_OUT_MUTE);
6212 }
6213 }
6214}
6215
6216/*
6217 * generic initialization of ADC, input mixers and output mixers
6218 */
6219static struct hda_verb alc260_volume_init_verbs[] = {
6220 /*
6221 * Unmute ADC0-1 and set the default input to mic-in
6222 */
6223 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6224 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6225 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6226 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006227
Kailang Yangdf694da2005-12-05 19:42:22 +01006228 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
6229 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006230 * Note: PASD motherboards uses the Line In 2 as the input for
6231 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01006232 */
6233 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006234 /* mute analog inputs */
6235 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6236 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6237 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6238 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6239 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006240
6241 /*
6242 * Set up output mixers (0x08 - 0x0a)
6243 */
6244 /* set vol=0 to output mixers */
6245 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6246 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6247 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6248 /* set up input amps for analog loopback */
6249 /* Amp Indices: DAC = 0, mixer = 1 */
6250 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6251 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6252 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6253 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6254 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6255 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006256
Kailang Yangdf694da2005-12-05 19:42:22 +01006257 { }
6258};
6259
6260static int alc260_parse_auto_config(struct hda_codec *codec)
6261{
6262 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006263 int err;
6264 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
6265
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006266 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
6267 alc260_ignore);
6268 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006269 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006270 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
6271 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01006272 return err;
Takashi Iwai603c4012008-07-30 15:01:44 +02006273 if (!spec->kctls.list)
Kailang Yangdf694da2005-12-05 19:42:22 +01006274 return 0; /* can't find valid BIOS pin config */
Takashi Iwai05f5f472009-08-25 13:10:18 +02006275 err = alc260_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006276 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006277 return err;
6278
6279 spec->multiout.max_channels = 2;
6280
Takashi Iwai0852d7a2009-02-11 11:35:15 +01006281 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +01006282 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
Takashi Iwai603c4012008-07-30 15:01:44 +02006283 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01006284 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +01006285
Takashi Iwaid88897e2008-10-31 15:01:37 +01006286 add_verb(spec, alc260_volume_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +01006287
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006288 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02006289 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006290
Takashi Iwai4a79ba32009-04-22 16:31:35 +02006291 alc_ssid_check(codec, 0x10, 0x15, 0x0f);
6292
Kailang Yangdf694da2005-12-05 19:42:22 +01006293 return 1;
6294}
6295
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006296/* additional initialization for auto-configuration model */
6297static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01006298{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006299 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006300 alc260_auto_init_multi_out(codec);
6301 alc260_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006302 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02006303 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01006304}
6305
Takashi Iwaicb53c622007-08-10 17:21:45 +02006306#ifdef CONFIG_SND_HDA_POWER_SAVE
6307static struct hda_amp_list alc260_loopbacks[] = {
6308 { 0x07, HDA_INPUT, 0 },
6309 { 0x07, HDA_INPUT, 1 },
6310 { 0x07, HDA_INPUT, 2 },
6311 { 0x07, HDA_INPUT, 3 },
6312 { 0x07, HDA_INPUT, 4 },
6313 { } /* end */
6314};
6315#endif
6316
Kailang Yangdf694da2005-12-05 19:42:22 +01006317/*
6318 * ALC260 configurations
6319 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006320static const char *alc260_models[ALC260_MODEL_LAST] = {
6321 [ALC260_BASIC] = "basic",
6322 [ALC260_HP] = "hp",
6323 [ALC260_HP_3013] = "hp-3013",
Takashi Iwai2922c9a2008-08-27 18:12:42 +02006324 [ALC260_HP_DC7600] = "hp-dc7600",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006325 [ALC260_FUJITSU_S702X] = "fujitsu",
6326 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006327 [ALC260_WILL] = "will",
6328 [ALC260_REPLACER_672V] = "replacer",
Michael Schwingencc959482009-02-22 18:58:45 +01006329 [ALC260_FAVORIT100] = "favorit100",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006330#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006331 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006332#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006333 [ALC260_AUTO] = "auto",
6334};
6335
6336static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01006337 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006338 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Michael Schwingencc959482009-02-22 18:58:45 +01006339 SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100),
Takashi Iwai9720b712007-03-13 21:46:23 +01006340 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwai4ac55982009-11-10 16:08:45 +01006341 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006342 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
Jaroslav Kysela34ec8a02008-07-10 14:49:19 +02006343 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
Kailang Yang3f878302008-08-26 13:02:23 +02006344 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006345 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
6346 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
6347 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
6348 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
6349 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
6350 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
6351 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
6352 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
6353 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006354 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006355 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02006356 {}
6357};
6358
Kailang Yangdf694da2005-12-05 19:42:22 +01006359static struct alc_config_preset alc260_presets[] = {
6360 [ALC260_BASIC] = {
6361 .mixers = { alc260_base_output_mixer,
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01006362 alc260_input_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01006363 .init_verbs = { alc260_init_verbs },
6364 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6365 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006366 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
Kailang Yangdf694da2005-12-05 19:42:22 +01006367 .adc_nids = alc260_adc_nids,
6368 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6369 .channel_mode = alc260_modes,
6370 .input_mux = &alc260_capture_source,
6371 },
6372 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006373 .mixers = { alc260_hp_output_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006374 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01006375 .init_verbs = { alc260_init_verbs,
6376 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01006377 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6378 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006379 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
6380 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01006381 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6382 .channel_mode = alc260_modes,
6383 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006384 .unsol_event = alc260_hp_unsol_event,
6385 .init_hook = alc260_hp_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01006386 },
Kailang Yang3f878302008-08-26 13:02:23 +02006387 [ALC260_HP_DC7600] = {
6388 .mixers = { alc260_hp_dc7600_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006389 alc260_input_mixer },
Kailang Yang3f878302008-08-26 13:02:23 +02006390 .init_verbs = { alc260_init_verbs,
6391 alc260_hp_dc7600_verbs },
6392 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6393 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006394 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
6395 .adc_nids = alc260_adc_nids_alt,
Kailang Yang3f878302008-08-26 13:02:23 +02006396 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6397 .channel_mode = alc260_modes,
6398 .input_mux = &alc260_capture_source,
6399 .unsol_event = alc260_hp_3012_unsol_event,
6400 .init_hook = alc260_hp_3012_automute,
6401 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006402 [ALC260_HP_3013] = {
6403 .mixers = { alc260_hp_3013_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006404 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01006405 .init_verbs = { alc260_hp_3013_init_verbs,
6406 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01006407 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6408 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006409 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
6410 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01006411 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6412 .channel_mode = alc260_modes,
6413 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006414 .unsol_event = alc260_hp_3013_unsol_event,
6415 .init_hook = alc260_hp_3013_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01006416 },
6417 [ALC260_FUJITSU_S702X] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006418 .mixers = { alc260_fujitsu_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01006419 .init_verbs = { alc260_fujitsu_init_verbs },
6420 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6421 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01006422 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
6423 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01006424 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6425 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006426 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
6427 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01006428 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006429 [ALC260_ACER] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006430 .mixers = { alc260_acer_mixer },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006431 .init_verbs = { alc260_acer_init_verbs },
6432 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6433 .dac_nids = alc260_dac_nids,
6434 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
6435 .adc_nids = alc260_dual_adc_nids,
6436 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6437 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006438 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
6439 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006440 },
Michael Schwingencc959482009-02-22 18:58:45 +01006441 [ALC260_FAVORIT100] = {
6442 .mixers = { alc260_favorit100_mixer },
6443 .init_verbs = { alc260_favorit100_init_verbs },
6444 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6445 .dac_nids = alc260_dac_nids,
6446 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
6447 .adc_nids = alc260_dual_adc_nids,
6448 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6449 .channel_mode = alc260_modes,
6450 .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources),
6451 .input_mux = alc260_favorit100_capture_sources,
6452 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006453 [ALC260_WILL] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006454 .mixers = { alc260_will_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006455 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
6456 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6457 .dac_nids = alc260_dac_nids,
6458 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
6459 .adc_nids = alc260_adc_nids,
6460 .dig_out_nid = ALC260_DIGOUT_NID,
6461 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6462 .channel_mode = alc260_modes,
6463 .input_mux = &alc260_capture_source,
6464 },
6465 [ALC260_REPLACER_672V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006466 .mixers = { alc260_replacer_672v_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006467 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
6468 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6469 .dac_nids = alc260_dac_nids,
6470 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
6471 .adc_nids = alc260_adc_nids,
6472 .dig_out_nid = ALC260_DIGOUT_NID,
6473 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6474 .channel_mode = alc260_modes,
6475 .input_mux = &alc260_capture_source,
6476 .unsol_event = alc260_replacer_672v_unsol_event,
6477 .init_hook = alc260_replacer_672v_automute,
6478 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006479#ifdef CONFIG_SND_DEBUG
6480 [ALC260_TEST] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006481 .mixers = { alc260_test_mixer },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006482 .init_verbs = { alc260_test_init_verbs },
6483 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
6484 .dac_nids = alc260_test_dac_nids,
6485 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
6486 .adc_nids = alc260_test_adc_nids,
6487 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6488 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006489 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
6490 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006491 },
6492#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01006493};
6494
Linus Torvalds1da177e2005-04-16 15:20:36 -07006495static int patch_alc260(struct hda_codec *codec)
6496{
6497 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006498 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006499
Takashi Iwaie560d8d2005-09-09 14:21:46 +02006500 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006501 if (spec == NULL)
6502 return -ENOMEM;
6503
6504 codec->spec = spec;
6505
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006506 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
6507 alc260_models,
6508 alc260_cfg_tbl);
6509 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02006510 snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai6c627f32009-05-18 12:33:36 +02006511 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +01006512 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02006513 }
6514
Kailang Yangdf694da2005-12-05 19:42:22 +01006515 if (board_config == ALC260_AUTO) {
6516 /* automatic parse from the BIOS config */
6517 err = alc260_parse_auto_config(codec);
6518 if (err < 0) {
6519 alc_free(codec);
6520 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006521 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006522 printk(KERN_INFO
6523 "hda_codec: Cannot set up configuration "
6524 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01006525 board_config = ALC260_BASIC;
6526 }
Takashi Iwai16ded522005-06-10 19:58:24 +02006527 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006528
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09006529 err = snd_hda_attach_beep_device(codec, 0x1);
6530 if (err < 0) {
6531 alc_free(codec);
6532 return err;
6533 }
6534
Kailang Yangdf694da2005-12-05 19:42:22 +01006535 if (board_config != ALC260_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02006536 setup_preset(codec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006537
Linus Torvalds1da177e2005-04-16 15:20:36 -07006538 spec->stream_analog_playback = &alc260_pcm_analog_playback;
6539 spec->stream_analog_capture = &alc260_pcm_analog_capture;
6540
Takashi Iwaia3bcba32005-12-06 19:05:29 +01006541 spec->stream_digital_playback = &alc260_pcm_digital_playback;
6542 spec->stream_digital_capture = &alc260_pcm_digital_capture;
6543
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01006544 if (!spec->adc_nids && spec->input_mux) {
6545 /* check whether NID 0x04 is valid */
6546 unsigned int wcap = get_wcaps(codec, 0x04);
Takashi Iwaia22d5432009-07-27 12:54:26 +02006547 wcap = get_wcaps_type(wcap);
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01006548 /* get type */
6549 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
6550 spec->adc_nids = alc260_adc_nids_alt;
6551 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
6552 } else {
6553 spec->adc_nids = alc260_adc_nids;
6554 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
6555 }
6556 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02006557 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01006558 set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006559
Takashi Iwai2134ea42008-01-10 16:53:55 +01006560 spec->vmaster_nid = 0x08;
6561
Linus Torvalds1da177e2005-04-16 15:20:36 -07006562 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01006563 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006564 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02006565#ifdef CONFIG_SND_HDA_POWER_SAVE
6566 if (!spec->loopback.amplist)
6567 spec->loopback.amplist = alc260_loopbacks;
6568#endif
Takashi Iwaidaead532008-11-28 12:55:36 +01006569 codec->proc_widget_hook = print_realtek_coef;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006570
6571 return 0;
6572}
6573
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006574
Linus Torvalds1da177e2005-04-16 15:20:36 -07006575/*
Takashi Iwai49535502009-06-30 15:28:30 +02006576 * ALC882/883/885/888/889 support
Linus Torvalds1da177e2005-04-16 15:20:36 -07006577 *
6578 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
6579 * configuration. Each pin widget can choose any input DACs and a mixer.
6580 * Each ADC is connected from a mixer of all inputs. This makes possible
6581 * 6-channel independent captures.
6582 *
6583 * In addition, an independent DAC for the multi-playback (not used in this
6584 * driver yet).
6585 */
Kailang Yangdf694da2005-12-05 19:42:22 +01006586#define ALC882_DIGOUT_NID 0x06
6587#define ALC882_DIGIN_NID 0x0a
Takashi Iwai49535502009-06-30 15:28:30 +02006588#define ALC883_DIGOUT_NID ALC882_DIGOUT_NID
6589#define ALC883_DIGIN_NID ALC882_DIGIN_NID
6590#define ALC1200_DIGOUT_NID 0x10
6591
Linus Torvalds1da177e2005-04-16 15:20:36 -07006592
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01006593static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006594 { 8, NULL }
6595};
6596
Takashi Iwai49535502009-06-30 15:28:30 +02006597/* DACs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006598static hda_nid_t alc882_dac_nids[4] = {
6599 /* front, rear, clfe, rear_surr */
6600 0x02, 0x03, 0x04, 0x05
6601};
Takashi Iwai49535502009-06-30 15:28:30 +02006602#define alc883_dac_nids alc882_dac_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07006603
Takashi Iwai49535502009-06-30 15:28:30 +02006604/* ADCs */
Kailang Yangdf694da2005-12-05 19:42:22 +01006605#define alc882_adc_nids alc880_adc_nids
6606#define alc882_adc_nids_alt alc880_adc_nids_alt
Takashi Iwai49535502009-06-30 15:28:30 +02006607#define alc883_adc_nids alc882_adc_nids_alt
6608static hda_nid_t alc883_adc_nids_alt[1] = { 0x08 };
6609static hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 };
6610#define alc889_adc_nids alc880_adc_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07006611
Takashi Iwaie1406342008-02-11 18:32:32 +01006612static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
6613static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
Takashi Iwai49535502009-06-30 15:28:30 +02006614#define alc883_capsrc_nids alc882_capsrc_nids_alt
6615static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
6616#define alc889_capsrc_nids alc882_capsrc_nids
Takashi Iwaie1406342008-02-11 18:32:32 +01006617
Linus Torvalds1da177e2005-04-16 15:20:36 -07006618/* input MUX */
6619/* FIXME: should be a matrix-type input source selection */
6620
6621static struct hda_input_mux alc882_capture_source = {
6622 .num_items = 4,
6623 .items = {
6624 { "Mic", 0x0 },
6625 { "Front Mic", 0x1 },
6626 { "Line", 0x2 },
6627 { "CD", 0x4 },
6628 },
6629};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02006630
Takashi Iwai49535502009-06-30 15:28:30 +02006631#define alc883_capture_source alc882_capture_source
6632
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02006633static struct hda_input_mux alc889_capture_source = {
6634 .num_items = 3,
6635 .items = {
6636 { "Front Mic", 0x0 },
6637 { "Mic", 0x3 },
6638 { "Line", 0x2 },
6639 },
6640};
6641
Kacper Szczesniak41d55452009-05-07 12:47:43 +02006642static struct hda_input_mux mb5_capture_source = {
6643 .num_items = 3,
6644 .items = {
6645 { "Mic", 0x1 },
6646 { "Line", 0x2 },
6647 { "CD", 0x4 },
6648 },
6649};
6650
Takashi Iwai49535502009-06-30 15:28:30 +02006651static struct hda_input_mux alc883_3stack_6ch_intel = {
6652 .num_items = 4,
6653 .items = {
6654 { "Mic", 0x1 },
6655 { "Front Mic", 0x0 },
6656 { "Line", 0x2 },
6657 { "CD", 0x4 },
6658 },
6659};
6660
6661static struct hda_input_mux alc883_lenovo_101e_capture_source = {
6662 .num_items = 2,
6663 .items = {
6664 { "Mic", 0x1 },
6665 { "Line", 0x2 },
6666 },
6667};
6668
6669static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
6670 .num_items = 4,
6671 .items = {
6672 { "Mic", 0x0 },
6673 { "iMic", 0x1 },
6674 { "Line", 0x2 },
6675 { "CD", 0x4 },
6676 },
6677};
6678
6679static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
6680 .num_items = 2,
6681 .items = {
6682 { "Mic", 0x0 },
6683 { "Int Mic", 0x1 },
6684 },
6685};
6686
6687static struct hda_input_mux alc883_lenovo_sky_capture_source = {
6688 .num_items = 3,
6689 .items = {
6690 { "Mic", 0x0 },
6691 { "Front Mic", 0x1 },
6692 { "Line", 0x4 },
6693 },
6694};
6695
6696static struct hda_input_mux alc883_asus_eee1601_capture_source = {
6697 .num_items = 2,
6698 .items = {
6699 { "Mic", 0x0 },
6700 { "Line", 0x2 },
6701 },
6702};
6703
6704static struct hda_input_mux alc889A_mb31_capture_source = {
6705 .num_items = 2,
6706 .items = {
6707 { "Mic", 0x0 },
6708 /* Front Mic (0x01) unused */
6709 { "Line", 0x2 },
6710 /* Line 2 (0x03) unused */
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02006711 /* CD (0x04) unused? */
Takashi Iwai49535502009-06-30 15:28:30 +02006712 },
6713};
6714
6715/*
6716 * 2ch mode
6717 */
6718static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
6719 { 2, NULL }
6720};
6721
Kailang Yangdf694da2005-12-05 19:42:22 +01006722/*
Kailang Yang272a5272007-05-14 11:00:38 +02006723 * 2ch mode
6724 */
6725static struct hda_verb alc882_3ST_ch2_init[] = {
6726 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6727 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6728 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6729 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6730 { } /* end */
6731};
6732
6733/*
Takashi Iwai49535502009-06-30 15:28:30 +02006734 * 4ch mode
6735 */
6736static struct hda_verb alc882_3ST_ch4_init[] = {
6737 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6738 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6739 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6740 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6741 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6742 { } /* end */
6743};
6744
6745/*
Kailang Yang272a5272007-05-14 11:00:38 +02006746 * 6ch mode
6747 */
6748static struct hda_verb alc882_3ST_ch6_init[] = {
6749 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6750 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6751 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
6752 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6753 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6754 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6755 { } /* end */
6756};
6757
Takashi Iwai49535502009-06-30 15:28:30 +02006758static struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
Kailang Yang272a5272007-05-14 11:00:38 +02006759 { 2, alc882_3ST_ch2_init },
Takashi Iwai49535502009-06-30 15:28:30 +02006760 { 4, alc882_3ST_ch4_init },
Kailang Yang272a5272007-05-14 11:00:38 +02006761 { 6, alc882_3ST_ch6_init },
6762};
6763
Takashi Iwai49535502009-06-30 15:28:30 +02006764#define alc883_3ST_6ch_modes alc882_3ST_6ch_modes
6765
Kailang Yang272a5272007-05-14 11:00:38 +02006766/*
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04306767 * 2ch mode
6768 */
6769static struct hda_verb alc883_3ST_ch2_clevo_init[] = {
6770 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
6771 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6772 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6773 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6774 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6775 { } /* end */
6776};
6777
6778/*
6779 * 4ch mode
6780 */
6781static struct hda_verb alc883_3ST_ch4_clevo_init[] = {
6782 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6783 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6784 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6785 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6786 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6787 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6788 { } /* end */
6789};
6790
6791/*
6792 * 6ch mode
6793 */
6794static struct hda_verb alc883_3ST_ch6_clevo_init[] = {
6795 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6796 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6797 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6798 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
6799 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6800 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6801 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6802 { } /* end */
6803};
6804
6805static struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
6806 { 2, alc883_3ST_ch2_clevo_init },
6807 { 4, alc883_3ST_ch4_clevo_init },
6808 { 6, alc883_3ST_ch6_clevo_init },
6809};
6810
6811
6812/*
Kailang Yangdf694da2005-12-05 19:42:22 +01006813 * 6ch mode
6814 */
6815static struct hda_verb alc882_sixstack_ch6_init[] = {
6816 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
6817 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6818 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6819 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6820 { } /* end */
6821};
6822
6823/*
6824 * 8ch mode
6825 */
6826static struct hda_verb alc882_sixstack_ch8_init[] = {
6827 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6828 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6829 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6830 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6831 { } /* end */
6832};
6833
6834static struct hda_channel_mode alc882_sixstack_modes[2] = {
6835 { 6, alc882_sixstack_ch6_init },
6836 { 8, alc882_sixstack_ch8_init },
6837};
6838
Takashi Iwai87350ad2007-08-16 18:19:38 +02006839/*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04006840 * macbook pro ALC885 can switch LineIn to LineOut without losing Mic
Takashi Iwai87350ad2007-08-16 18:19:38 +02006841 */
6842
6843/*
6844 * 2ch mode
6845 */
6846static struct hda_verb alc885_mbp_ch2_init[] = {
6847 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6848 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6849 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6850 { } /* end */
6851};
6852
6853/*
Takashi Iwaia3f730a2009-08-31 08:15:26 +02006854 * 4ch mode
Takashi Iwai87350ad2007-08-16 18:19:38 +02006855 */
Takashi Iwaia3f730a2009-08-31 08:15:26 +02006856static struct hda_verb alc885_mbp_ch4_init[] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02006857 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6858 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6859 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6860 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6861 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6862 { } /* end */
6863};
6864
Takashi Iwaia3f730a2009-08-31 08:15:26 +02006865static struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02006866 { 2, alc885_mbp_ch2_init },
Takashi Iwaia3f730a2009-08-31 08:15:26 +02006867 { 4, alc885_mbp_ch4_init },
Takashi Iwai87350ad2007-08-16 18:19:38 +02006868};
6869
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02006870/*
6871 * 2ch
6872 * Speakers/Woofer/HP = Front
6873 * LineIn = Input
6874 */
6875static struct hda_verb alc885_mb5_ch2_init[] = {
6876 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6877 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6878 { } /* end */
6879};
6880
6881/*
6882 * 6ch mode
6883 * Speakers/HP = Front
6884 * Woofer = LFE
6885 * LineIn = Surround
6886 */
6887static struct hda_verb alc885_mb5_ch6_init[] = {
6888 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6889 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6890 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
6891 { } /* end */
6892};
6893
6894static struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
6895 { 2, alc885_mb5_ch2_init },
6896 { 6, alc885_mb5_ch6_init },
6897};
Takashi Iwai87350ad2007-08-16 18:19:38 +02006898
Takashi Iwai49535502009-06-30 15:28:30 +02006899
6900/*
6901 * 2ch mode
6902 */
6903static struct hda_verb alc883_4ST_ch2_init[] = {
6904 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6905 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6906 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6907 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6908 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6909 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6910 { } /* end */
6911};
6912
6913/*
6914 * 4ch mode
6915 */
6916static struct hda_verb alc883_4ST_ch4_init[] = {
6917 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6918 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6919 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6920 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6921 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6922 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6923 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6924 { } /* end */
6925};
6926
6927/*
6928 * 6ch mode
6929 */
6930static struct hda_verb alc883_4ST_ch6_init[] = {
6931 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6932 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6933 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6934 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6935 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
6936 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6937 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6938 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6939 { } /* end */
6940};
6941
6942/*
6943 * 8ch mode
6944 */
6945static struct hda_verb alc883_4ST_ch8_init[] = {
6946 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6947 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6948 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
6949 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6950 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6951 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
6952 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6953 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6954 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6955 { } /* end */
6956};
6957
6958static struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
6959 { 2, alc883_4ST_ch2_init },
6960 { 4, alc883_4ST_ch4_init },
6961 { 6, alc883_4ST_ch6_init },
6962 { 8, alc883_4ST_ch8_init },
6963};
6964
6965
6966/*
6967 * 2ch mode
6968 */
6969static struct hda_verb alc883_3ST_ch2_intel_init[] = {
6970 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6971 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6972 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6973 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6974 { } /* end */
6975};
6976
6977/*
6978 * 4ch mode
6979 */
6980static struct hda_verb alc883_3ST_ch4_intel_init[] = {
6981 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6982 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6983 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6984 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6985 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6986 { } /* end */
6987};
6988
6989/*
6990 * 6ch mode
6991 */
6992static struct hda_verb alc883_3ST_ch6_intel_init[] = {
6993 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6994 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6995 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
6996 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6997 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6998 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6999 { } /* end */
7000};
7001
7002static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
7003 { 2, alc883_3ST_ch2_intel_init },
7004 { 4, alc883_3ST_ch4_intel_init },
7005 { 6, alc883_3ST_ch6_intel_init },
7006};
7007
7008/*
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007009 * 2ch mode
7010 */
7011static struct hda_verb alc889_ch2_intel_init[] = {
7012 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7013 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 },
7014 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 },
7015 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00 },
7016 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7017 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7018 { } /* end */
7019};
7020
7021/*
Takashi Iwai49535502009-06-30 15:28:30 +02007022 * 6ch mode
7023 */
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007024static struct hda_verb alc889_ch6_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007025 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7026 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7027 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7028 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7029 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007030 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7031 { } /* end */
7032};
7033
7034/*
7035 * 8ch mode
7036 */
7037static struct hda_verb alc889_ch8_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007038 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7039 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7040 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7041 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7042 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x03 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007043 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7044 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007045 { } /* end */
7046};
7047
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007048static struct hda_channel_mode alc889_8ch_intel_modes[3] = {
7049 { 2, alc889_ch2_intel_init },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007050 { 6, alc889_ch6_intel_init },
7051 { 8, alc889_ch8_intel_init },
7052};
7053
7054/*
7055 * 6ch mode
7056 */
Takashi Iwai49535502009-06-30 15:28:30 +02007057static struct hda_verb alc883_sixstack_ch6_init[] = {
7058 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7059 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7060 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7061 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7062 { } /* end */
7063};
7064
7065/*
7066 * 8ch mode
7067 */
7068static struct hda_verb alc883_sixstack_ch8_init[] = {
7069 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7070 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7071 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7072 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7073 { } /* end */
7074};
7075
7076static struct hda_channel_mode alc883_sixstack_modes[2] = {
7077 { 6, alc883_sixstack_ch6_init },
7078 { 8, alc883_sixstack_ch8_init },
7079};
7080
7081
Linus Torvalds1da177e2005-04-16 15:20:36 -07007082/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
7083 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
7084 */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01007085static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02007086 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007087 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007088 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007089 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007090 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7091 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007092 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7093 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007094 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007095 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007096 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7097 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7098 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7099 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7100 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7101 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007102 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007103 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7104 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007105 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007106 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007107 { } /* end */
7108};
7109
Takashi Iwai87350ad2007-08-16 18:19:38 +02007110static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007111 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7112 HDA_BIND_MUTE ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
7113 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7114 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT),
7115 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01007116 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7117 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02007118 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
7119 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01007120 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02007121 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
7122 { } /* end */
7123};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007124
7125static struct snd_kcontrol_new alc885_mb5_mixer[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007126 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7127 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
7128 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
7129 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
7130 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7131 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
7132 HDA_CODEC_VOLUME("HP Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
7133 HDA_BIND_MUTE ("HP Playback Switch", 0x0f, 0x02, HDA_INPUT),
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007134 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7135 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7136 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
7137 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
7138 HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT),
7139 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0x00, HDA_INPUT),
7140 { } /* end */
7141};
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007142
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08007143static struct snd_kcontrol_new alc885_imac91_mixer[] = {
7144 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7145 HDA_BIND_MUTE ("Line-Out Playback Switch", 0x0c, 0x02, HDA_INPUT),
7146 HDA_CODEC_MUTE ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT),
7147 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
7148 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7149 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7150 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
7151 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
7152 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
7153 { } /* end */
7154};
7155
7156
Kailang Yangbdd148a2007-05-08 15:19:08 +02007157static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
7158 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7159 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7160 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7161 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7162 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7163 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7164 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7165 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7166 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02007167 { } /* end */
7168};
7169
Kailang Yang272a5272007-05-14 11:00:38 +02007170static struct snd_kcontrol_new alc882_targa_mixer[] = {
7171 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7172 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7173 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7174 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7175 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7176 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7177 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7178 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7179 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02007180 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007181 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7182 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02007183 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007184 { } /* end */
7185};
7186
7187/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
7188 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
7189 */
7190static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
7191 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7192 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7193 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7194 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
7195 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7196 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7197 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7198 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7199 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
7200 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
7201 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7202 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02007203 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007204 { } /* end */
7205};
7206
Takashi Iwai914759b2007-09-06 14:52:04 +02007207static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
7208 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7209 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7210 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7211 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7212 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7213 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7214 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7215 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7216 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7217 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02007218 { } /* end */
7219};
7220
Kailang Yangdf694da2005-12-05 19:42:22 +01007221static struct snd_kcontrol_new alc882_chmode_mixer[] = {
7222 {
7223 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7224 .name = "Channel Mode",
7225 .info = alc_ch_mode_info,
7226 .get = alc_ch_mode_get,
7227 .put = alc_ch_mode_put,
7228 },
7229 { } /* end */
7230};
7231
Takashi Iwai49535502009-06-30 15:28:30 +02007232static struct hda_verb alc882_base_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007233 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007234 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7235 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7236 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007237 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02007238 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7239 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7240 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007241 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02007242 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7243 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7244 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007245 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02007246 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7247 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7248 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007249
Takashi Iwaicb638122009-07-03 10:56:10 +02007250 /* mute analog input loopbacks */
7251 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7252 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7253 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7254 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7255 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7256
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007257 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007258 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007259 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007260 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007261 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007262 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007263 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007264 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007265 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007266 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007267 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007268 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007269 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007270 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007271 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007272 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007273 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02007274 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007275 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7276 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02007277 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007278 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7279 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02007280 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007281 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7282 /* Line-2 In: Headphone output (output 0 - 0x0c) */
7283 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7284 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7285 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007286 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02007287 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007288
7289 /* FIXME: use matrix-type input source selection */
7290 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007291 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02007292 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7293 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7294 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7295 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007296 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02007297 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7298 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7299 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7300 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai05acb862005-06-10 19:50:25 +02007301 /* ADC2: mute amp left and right */
7302 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02007303 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02007304 /* ADC3: mute amp left and right */
7305 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02007306 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007307
7308 { }
7309};
7310
Takashi Iwai49535502009-06-30 15:28:30 +02007311static struct hda_verb alc882_adc1_init_verbs[] = {
7312 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
7313 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7314 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7315 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7316 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7317 /* ADC1: mute amp left and right */
7318 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7319 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
7320 { }
7321};
7322
Takashi Iwai4b146cb2006-07-28 14:42:36 +02007323static struct hda_verb alc882_eapd_verbs[] = {
7324 /* change to EAPD mode */
7325 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007326 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007327 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02007328};
7329
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007330static struct hda_verb alc889_eapd_verbs[] = {
7331 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
7332 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
7333 { }
7334};
7335
Wu Fengguang6732bd02009-07-30 09:19:14 +02007336static struct hda_verb alc_hp15_unsol_verbs[] = {
7337 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
7338 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7339 {}
7340};
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007341
7342static struct hda_verb alc885_init_verbs[] = {
7343 /* Front mixer: unmute input/output amp left and right (volume = 0) */
7344 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7345 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7346 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7347 /* Rear mixer */
7348 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7349 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7350 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7351 /* CLFE mixer */
7352 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7353 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7354 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7355 /* Side mixer */
7356 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7357 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7358 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7359
7360 /* mute analog input loopbacks */
7361 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7362 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7363 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7364
7365 /* Front HP Pin: output 0 (0x0c) */
Wu Fengguang6732bd02009-07-30 09:19:14 +02007366 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007367 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7368 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7369 /* Front Pin: output 0 (0x0c) */
7370 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7371 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7372 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7373 /* Rear Pin: output 1 (0x0d) */
7374 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7375 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7376 {0x19, AC_VERB_SET_CONNECT_SEL, 0x01},
7377 /* CLFE Pin: output 2 (0x0e) */
7378 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7379 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7380 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
7381 /* Side Pin: output 3 (0x0f) */
7382 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7383 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7384 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
7385 /* Mic (rear) pin: input vref at 80% */
7386 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7387 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7388 /* Front Mic pin: input vref at 80% */
7389 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7390 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7391 /* Line In pin: input */
7392 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7393 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7394
7395 /* Mixer elements: 0x18, , 0x1a, 0x1b */
7396 /* Input mixer1 */
7397 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
7398 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7399 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7400 /* Input mixer2 */
7401 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7402 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7403 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7404 /* Input mixer3 */
7405 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
7406 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7407 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7408 /* ADC2: mute amp left and right */
7409 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7410 /* ADC3: mute amp left and right */
7411 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7412
7413 { }
7414};
7415
7416static struct hda_verb alc885_init_input_verbs[] = {
7417 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7418 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
7419 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
7420 { }
7421};
7422
7423
7424/* Unmute Selector 24h and set the default input to front mic */
7425static struct hda_verb alc889_init_input_verbs[] = {
7426 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
7427 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7428 { }
7429};
7430
7431
Takashi Iwai49535502009-06-30 15:28:30 +02007432#define alc883_init_verbs alc882_base_init_verbs
7433
Tobin Davis9102cd12006-12-15 10:02:12 +01007434/* Mac Pro test */
7435static struct snd_kcontrol_new alc882_macpro_mixer[] = {
7436 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7437 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7438 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
7439 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
7440 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007441 /* FIXME: this looks suspicious...
Jaroslav Kyselad355c82a2009-11-03 15:47:25 +01007442 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT),
7443 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007444 */
Tobin Davis9102cd12006-12-15 10:02:12 +01007445 { } /* end */
7446};
7447
7448static struct hda_verb alc882_macpro_init_verbs[] = {
7449 /* Front mixer: unmute input/output amp left and right (volume = 0) */
7450 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7451 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7452 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7453 /* Front Pin: output 0 (0x0c) */
7454 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7455 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7456 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7457 /* Front Mic pin: input vref at 80% */
7458 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7459 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7460 /* Speaker: output */
7461 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7462 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7463 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
7464 /* Headphone output (output 0 - 0x0c) */
7465 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7466 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7467 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
7468
7469 /* FIXME: use matrix-type input source selection */
7470 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7471 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
7472 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7473 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7474 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7475 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7476 /* Input mixer2 */
7477 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7478 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7479 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7480 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7481 /* Input mixer3 */
7482 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7483 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7484 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7485 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7486 /* ADC1: mute amp left and right */
7487 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7488 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
7489 /* ADC2: mute amp left and right */
7490 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7491 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7492 /* ADC3: mute amp left and right */
7493 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7494 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7495
7496 { }
7497};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007498
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007499/* Macbook 5,1 */
7500static struct hda_verb alc885_mb5_init_verbs[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007501 /* DACs */
7502 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7503 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7504 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7505 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007506 /* Front mixer */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007507 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7508 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7509 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007510 /* Surround mixer */
7511 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7512 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7513 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7514 /* LFE mixer */
7515 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7516 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7517 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7518 /* HP mixer */
7519 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7520 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7521 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7522 /* Front Pin (0x0c) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007523 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
7524 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007525 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
7526 /* LFE Pin (0x0e) */
7527 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
7528 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7529 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
7530 /* HP Pin (0x0f) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007531 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7532 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007533 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007534 /* Front Mic pin: input vref at 80% */
7535 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7536 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7537 /* Line In pin */
7538 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7539 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7540
7541 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7542 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7543 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7544 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7545 { }
7546};
7547
Takashi Iwai87350ad2007-08-16 18:19:38 +02007548/* Macbook Pro rev3 */
7549static struct hda_verb alc885_mbp3_init_verbs[] = {
7550 /* Front mixer: unmute input/output amp left and right (volume = 0) */
7551 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7552 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7553 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7554 /* Rear mixer */
7555 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7556 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7557 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007558 /* HP mixer */
7559 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7560 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7561 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai87350ad2007-08-16 18:19:38 +02007562 /* Front Pin: output 0 (0x0c) */
7563 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7564 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7565 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007566 /* HP Pin: output 0 (0x0e) */
Takashi Iwai87350ad2007-08-16 18:19:38 +02007567 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007568 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7569 {0x15, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai87350ad2007-08-16 18:19:38 +02007570 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7571 /* Mic (rear) pin: input vref at 80% */
7572 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7573 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7574 /* Front Mic pin: input vref at 80% */
7575 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7576 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7577 /* Line In pin: use output 1 when in LineOut mode */
7578 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7579 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7580 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
7581
7582 /* FIXME: use matrix-type input source selection */
7583 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7584 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
7585 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7586 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7587 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7588 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7589 /* Input mixer2 */
7590 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7591 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7592 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7593 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7594 /* Input mixer3 */
7595 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7596 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7597 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7598 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7599 /* ADC1: mute amp left and right */
7600 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7601 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
7602 /* ADC2: mute amp left and right */
7603 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7604 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7605 /* ADC3: mute amp left and right */
7606 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7607 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7608
7609 { }
7610};
7611
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08007612/* iMac 9,1 */
7613static struct hda_verb alc885_imac91_init_verbs[] = {
7614 /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */
7615 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7616 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7617 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7618 /* Rear mixer */
7619 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7620 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7621 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7622 /* HP Pin: output 0 (0x0c) */
7623 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7624 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7625 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7626 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7627 /* Internal Speakers: output 0 (0x0d) */
7628 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7629 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7630 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7631 /* Mic (rear) pin: input vref at 80% */
7632 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7633 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7634 /* Front Mic pin: input vref at 80% */
7635 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7636 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7637 /* Line In pin: use output 1 when in LineOut mode */
7638 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7639 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7640 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
7641
7642 /* FIXME: use matrix-type input source selection */
7643 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7644 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
7645 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7646 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7647 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7648 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7649 /* Input mixer2 */
7650 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7651 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7652 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7653 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7654 /* Input mixer3 */
7655 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7656 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7657 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7658 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7659 /* ADC1: mute amp left and right */
7660 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7661 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
7662 /* ADC2: mute amp left and right */
7663 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7664 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7665 /* ADC3: mute amp left and right */
7666 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7667 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7668
7669 { }
7670};
7671
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007672/* iMac 24 mixer. */
7673static struct snd_kcontrol_new alc885_imac24_mixer[] = {
7674 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7675 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
7676 { } /* end */
7677};
7678
7679/* iMac 24 init verbs. */
7680static struct hda_verb alc885_imac24_init_verbs[] = {
7681 /* Internal speakers: output 0 (0x0c) */
7682 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7683 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7684 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
7685 /* Internal speakers: output 0 (0x0c) */
7686 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7687 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7688 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
7689 /* Headphone: output 0 (0x0c) */
7690 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7691 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7692 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7693 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7694 /* Front Mic: input vref at 80% */
7695 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7696 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7697 { }
7698};
7699
7700/* Toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02007701static void alc885_imac24_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007702{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007703 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007704
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007705 spec->autocfg.hp_pins[0] = 0x14;
7706 spec->autocfg.speaker_pins[0] = 0x18;
7707 spec->autocfg.speaker_pins[1] = 0x1a;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007708}
7709
Takashi Iwai4f5d17062009-08-11 18:17:46 +02007710static void alc885_mbp3_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007711{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007712 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007713
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007714 spec->autocfg.hp_pins[0] = 0x15;
7715 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai87350ad2007-08-16 18:19:38 +02007716}
7717
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08007718static void alc885_imac91_automute(struct hda_codec *codec)
7719{
7720 unsigned int present;
7721
7722 present = snd_hda_codec_read(codec, 0x14, 0,
7723 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7724 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7725 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7726 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
7727 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7728
7729}
7730
7731static void alc885_imac91_unsol_event(struct hda_codec *codec,
7732 unsigned int res)
7733{
7734 /* Headphone insertion or removal. */
7735 if ((res >> 26) == ALC880_HP_EVENT)
7736 alc885_imac91_automute(codec);
7737}
Takashi Iwai87350ad2007-08-16 18:19:38 +02007738
Kailang Yang272a5272007-05-14 11:00:38 +02007739static struct hda_verb alc882_targa_verbs[] = {
7740 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7741 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7742
7743 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7744 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02007745
Kailang Yang272a5272007-05-14 11:00:38 +02007746 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
7747 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
7748 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
7749
7750 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yang272a5272007-05-14 11:00:38 +02007751 { } /* end */
7752};
7753
7754/* toggle speaker-output according to the hp-jack state */
7755static void alc882_targa_automute(struct hda_codec *codec)
7756{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007757 struct alc_spec *spec = codec->spec;
7758 alc_automute_amp(codec);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02007759 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007760 spec->jack_present ? 1 : 3);
7761}
7762
Takashi Iwai4f5d17062009-08-11 18:17:46 +02007763static void alc882_targa_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007764{
7765 struct alc_spec *spec = codec->spec;
7766
7767 spec->autocfg.hp_pins[0] = 0x14;
7768 spec->autocfg.speaker_pins[0] = 0x1b;
Kailang Yang272a5272007-05-14 11:00:38 +02007769}
7770
7771static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
7772{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007773 if ((res >> 26) == ALC880_HP_EVENT)
Kailang Yang272a5272007-05-14 11:00:38 +02007774 alc882_targa_automute(codec);
Kailang Yang272a5272007-05-14 11:00:38 +02007775}
7776
7777static struct hda_verb alc882_asus_a7j_verbs[] = {
7778 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7779 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7780
7781 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7782 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7783 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02007784
Kailang Yang272a5272007-05-14 11:00:38 +02007785 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
7786 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
7787 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
7788
7789 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
7790 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
7791 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
7792 { } /* end */
7793};
7794
Takashi Iwai914759b2007-09-06 14:52:04 +02007795static struct hda_verb alc882_asus_a7m_verbs[] = {
7796 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7797 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7798
7799 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7800 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7801 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02007802
Takashi Iwai914759b2007-09-06 14:52:04 +02007803 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
7804 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
7805 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
7806
7807 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
7808 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
7809 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
7810 { } /* end */
7811};
7812
Tobin Davis9102cd12006-12-15 10:02:12 +01007813static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
7814{
7815 unsigned int gpiostate, gpiomask, gpiodir;
7816
7817 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
7818 AC_VERB_GET_GPIO_DATA, 0);
7819
7820 if (!muted)
7821 gpiostate |= (1 << pin);
7822 else
7823 gpiostate &= ~(1 << pin);
7824
7825 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
7826 AC_VERB_GET_GPIO_MASK, 0);
7827 gpiomask |= (1 << pin);
7828
7829 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
7830 AC_VERB_GET_GPIO_DIRECTION, 0);
7831 gpiodir |= (1 << pin);
7832
7833
7834 snd_hda_codec_write(codec, codec->afg, 0,
7835 AC_VERB_SET_GPIO_MASK, gpiomask);
7836 snd_hda_codec_write(codec, codec->afg, 0,
7837 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
7838
7839 msleep(1);
7840
7841 snd_hda_codec_write(codec, codec->afg, 0,
7842 AC_VERB_SET_GPIO_DATA, gpiostate);
7843}
7844
Takashi Iwai7debbe52007-08-16 15:01:03 +02007845/* set up GPIO at initialization */
7846static void alc885_macpro_init_hook(struct hda_codec *codec)
7847{
7848 alc882_gpio_mute(codec, 0, 0);
7849 alc882_gpio_mute(codec, 1, 0);
7850}
7851
7852/* set up GPIO and update auto-muting at initialization */
7853static void alc885_imac24_init_hook(struct hda_codec *codec)
7854{
7855 alc885_macpro_init_hook(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +02007856 alc_automute_amp(codec);
Takashi Iwai7debbe52007-08-16 15:01:03 +02007857}
7858
Kailang Yangdf694da2005-12-05 19:42:22 +01007859/*
7860 * generic initialization of ADC, input mixers and output mixers
7861 */
Takashi Iwai49535502009-06-30 15:28:30 +02007862static struct hda_verb alc883_auto_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01007863 /*
7864 * Unmute ADC0-2 and set the default input to mic-in
7865 */
Kailang Yangdf694da2005-12-05 19:42:22 +01007866 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7867 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7868 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7869 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7870
Takashi Iwaicb53c622007-08-10 17:21:45 +02007871 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01007872 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007873 * Note: PASD motherboards uses the Line In 2 as the input for
7874 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01007875 */
7876 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02007877 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7878 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7879 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7880 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7881 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01007882
7883 /*
7884 * Set up output mixers (0x0c - 0x0f)
7885 */
7886 /* set vol=0 to output mixers */
7887 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7888 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7889 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7890 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7891 /* set up input amps for analog loopback */
7892 /* Amp Indices: DAC = 0, mixer = 1 */
7893 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7894 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7895 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7896 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7897 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7898 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7899 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7900 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7901 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7902 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7903
7904 /* FIXME: use matrix-type input source selection */
7905 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Kailang Yangdf694da2005-12-05 19:42:22 +01007906 /* Input mixer2 */
7907 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
7908 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
7909 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
7910 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
7911 /* Input mixer3 */
7912 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
7913 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
7914 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
7915 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
7916
7917 { }
7918};
7919
Torben Schulzeb4c41d2009-05-18 15:02:35 +02007920/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
7921static struct hda_verb alc889A_mb31_ch2_init[] = {
7922 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
7923 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
7924 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
7925 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
7926 { } /* end */
7927};
7928
7929/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */
7930static struct hda_verb alc889A_mb31_ch4_init[] = {
7931 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
7932 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
7933 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
7934 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
7935 { } /* end */
7936};
7937
7938/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */
7939static struct hda_verb alc889A_mb31_ch5_init[] = {
7940 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */
7941 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
7942 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
7943 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
7944 { } /* end */
7945};
7946
7947/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */
7948static struct hda_verb alc889A_mb31_ch6_init[] = {
7949 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */
7950 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */
7951 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
7952 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
7953 { } /* end */
7954};
7955
7956static struct hda_channel_mode alc889A_mb31_6ch_modes[4] = {
7957 { 2, alc889A_mb31_ch2_init },
7958 { 4, alc889A_mb31_ch4_init },
7959 { 5, alc889A_mb31_ch5_init },
7960 { 6, alc889A_mb31_ch6_init },
7961};
7962
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007963static struct hda_verb alc883_medion_eapd_verbs[] = {
7964 /* eanable EAPD on medion laptop */
7965 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
7966 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
7967 { }
7968};
7969
Takashi Iwai49535502009-06-30 15:28:30 +02007970#define alc883_base_mixer alc882_base_mixer
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007971
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007972static struct snd_kcontrol_new alc883_mitac_mixer[] = {
7973 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7974 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7975 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7976 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7977 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7978 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7979 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7980 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7981 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7982 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7983 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7984 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
7985 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007986 { } /* end */
7987};
7988
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007989static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01007990 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7991 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
7992 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7993 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
7994 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7995 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7996 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7997 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7998 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7999 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01008000 { } /* end */
8001};
8002
Jiang zhefb97dc62008-03-06 11:07:11 +01008003static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
8004 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8005 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8006 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8007 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8008 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8009 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8010 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8011 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8012 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8013 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01008014 { } /* end */
8015};
8016
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008017static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
8018 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8019 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8020 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8021 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8022 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8023 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8024 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8025 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008026 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008027 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8028 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008029 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008030 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008031 { } /* end */
8032};
8033
8034static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
8035 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8036 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8037 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8038 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8039 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8040 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8041 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8042 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8043 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8044 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8045 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8046 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8047 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8048 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008049 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008050 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8051 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008052 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008053 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008054 { } /* end */
8055};
8056
Jiang zhe17bba1b2008-06-04 12:11:07 +02008057static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
8058 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8059 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8060 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8061 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8062 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
8063 HDA_OUTPUT),
8064 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8065 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8066 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8067 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8068 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8069 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8070 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8071 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8072 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8073 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
8074 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8075 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8076 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
8077 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008078 { } /* end */
8079};
8080
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008081static struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
8082 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8083 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8084 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8085 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8086 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
8087 HDA_OUTPUT),
8088 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8089 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8090 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8091 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8092 HDA_BIND_MUTE("Speaker Playback Switch", 0x0f, 2, HDA_INPUT),
8093 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8094 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8095 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8096 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
8097 HDA_CODEC_VOLUME("Mic Boost", 0x1b, 0, HDA_INPUT),
8098 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
8099 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8100 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
8101 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8102 { } /* end */
8103};
8104
Takashi Iwaid1d985f2006-11-23 19:27:12 +01008105static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02008106 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008107 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008108 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008109 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008110 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8111 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008112 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8113 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008114 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8115 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8116 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8117 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8118 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8119 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008120 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008121 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8122 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008123 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008124 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008125 { } /* end */
8126};
8127
Sasha Alexandrc2592492009-06-16 14:52:54 -04008128static struct snd_kcontrol_new alc883_targa_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02008129 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008130 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008131 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008132 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008133 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8134 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8135 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8136 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8137 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8138 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8139 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8140 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8141 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8142 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8143 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008144 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008145 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008146 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008147};
Kailang Yangccc656c2006-10-17 12:32:26 +02008148
Sasha Alexandrc2592492009-06-16 14:52:54 -04008149static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02008150 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008151 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008152 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008153 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008154 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8155 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8156 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008157 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008158 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe4383fae2008-04-14 12:58:57 +02008159 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8160 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8161 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008162 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008163};
Kailang Yangccc656c2006-10-17 12:32:26 +02008164
Takashi Iwaib99dba32009-09-17 18:23:00 +02008165static struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
8166 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8167 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
8168 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8169 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8170 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8171 { } /* end */
8172};
8173
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008174static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
8175 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8176 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01008177 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8178 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008179 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8180 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8181 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8182 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008183 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008184};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008185
Kailang Yang272a5272007-05-14 11:00:38 +02008186static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
8187 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8188 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
8189 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8190 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8191 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8192 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8193 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8194 HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8195 HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008196 { } /* end */
8197};
8198
8199static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
8200 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8201 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8202 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8203 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8204 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8205 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8206 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8207 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8208 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008209 { } /* end */
Kailang Yangea1fb292008-08-26 12:58:38 +02008210};
Kailang Yang272a5272007-05-14 11:00:38 +02008211
Tobin Davis2880a862007-08-07 11:50:26 +02008212static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02008213 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8214 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02008215 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02008216 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8217 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02008218 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8219 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8220 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02008221 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02008222};
Tobin Davis2880a862007-08-07 11:50:26 +02008223
Tony Vroond2fd4b02009-06-21 00:40:10 +01008224static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
8225 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8226 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8227 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8228 HDA_BIND_MUTE("LFE Playback Switch", 0x0f, 2, HDA_INPUT),
Tony Vroon684a8842009-06-26 09:27:50 +01008229 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8230 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01008231 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("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8234 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8235 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8236 { } /* end */
8237};
8238
Kailang Yange2757d52008-08-26 13:17:46 +02008239static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
8240 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8241 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8242 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
8243 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
8244 HDA_CODEC_VOLUME_MONO("Center Playback Volume",
8245 0x0d, 1, 0x0, HDA_OUTPUT),
8246 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
8247 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
8248 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
8249 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8250 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02008251 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8252 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8253 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8254 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8255 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8256 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8257 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8258 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8259 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
8260 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02008261 { } /* end */
8262};
8263
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008264static struct snd_kcontrol_new alc889A_mb31_mixer[] = {
8265 /* Output mixers */
8266 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8267 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
8268 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
8269 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
8270 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00,
8271 HDA_OUTPUT),
8272 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT),
8273 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT),
8274 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT),
8275 /* Output switches */
8276 HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT),
8277 HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT),
8278 HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT),
8279 /* Boost mixers */
8280 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
8281 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
8282 /* Input mixers */
8283 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
8284 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
8285 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8286 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8287 { } /* end */
8288};
8289
Guido Günther3e1647c2009-06-05 00:47:26 +02008290static struct snd_kcontrol_new alc883_vaiott_mixer[] = {
8291 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8292 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8293 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8294 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8295 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
8296 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8297 { } /* end */
8298};
8299
Kailang Yange2757d52008-08-26 13:17:46 +02008300static struct hda_bind_ctls alc883_bind_cap_vol = {
8301 .ops = &snd_hda_bind_vol,
8302 .values = {
8303 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
8304 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
8305 0
8306 },
8307};
8308
8309static struct hda_bind_ctls alc883_bind_cap_switch = {
8310 .ops = &snd_hda_bind_sw,
8311 .values = {
8312 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
8313 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
8314 0
8315 },
8316};
8317
8318static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
8319 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8320 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8321 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8322 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8323 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8324 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8325 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8326 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008327 { } /* end */
8328};
8329
8330static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02008331 HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
8332 HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
8333 {
8334 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8335 /* .name = "Capture Source", */
8336 .name = "Input Source",
8337 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01008338 .info = alc_mux_enum_info,
8339 .get = alc_mux_enum_get,
8340 .put = alc_mux_enum_put,
Kailang Yange2757d52008-08-26 13:17:46 +02008341 },
8342 { } /* end */
8343};
8344
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008345static struct snd_kcontrol_new alc883_chmode_mixer[] = {
8346 {
8347 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8348 .name = "Channel Mode",
8349 .info = alc_ch_mode_info,
8350 .get = alc_ch_mode_get,
8351 .put = alc_ch_mode_put,
8352 },
8353 { } /* end */
8354};
8355
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008356/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008357static void alc883_mitac_setup(struct hda_codec *codec)
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008358{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008359 struct alc_spec *spec = codec->spec;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008360
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008361 spec->autocfg.hp_pins[0] = 0x15;
8362 spec->autocfg.speaker_pins[0] = 0x14;
8363 spec->autocfg.speaker_pins[1] = 0x17;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008364}
8365
8366/* auto-toggle front mic */
8367/*
8368static void alc883_mitac_mic_automute(struct hda_codec *codec)
8369{
Wu Fengguang864f92b2009-11-18 12:38:02 +08008370 unsigned char bits = snd_hda_jack_detect(codec, 0x18) ? HDA_AMP_MUTE : 0;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008371
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008372 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
8373}
8374*/
8375
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008376static struct hda_verb alc883_mitac_verbs[] = {
8377 /* HP */
8378 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8379 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8380 /* Subwoofer */
8381 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
8382 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8383
8384 /* enable unsolicited event */
8385 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8386 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
8387
8388 { } /* end */
8389};
8390
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04308391static struct hda_verb alc883_clevo_m540r_verbs[] = {
8392 /* HP */
8393 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8394 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8395 /* Int speaker */
8396 /*{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},*/
8397
8398 /* enable unsolicited event */
8399 /*
8400 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8401 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
8402 */
8403
8404 { } /* end */
8405};
8406
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008407static struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01008408 /* HP */
8409 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8410 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8411 /* Int speaker */
8412 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
8413 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8414
8415 /* enable unsolicited event */
8416 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008417 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01008418
8419 { } /* end */
8420};
8421
Jiang zhefb97dc62008-03-06 11:07:11 +01008422static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
8423 /* HP */
8424 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8425 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8426 /* Subwoofer */
8427 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
8428 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8429
8430 /* enable unsolicited event */
8431 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8432
8433 { } /* end */
8434};
8435
Sasha Alexandrc2592492009-06-16 14:52:54 -04008436static struct hda_verb alc883_targa_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02008437 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8438 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8439
8440 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8441 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008442
David Heidelberger64a8be72009-06-08 16:15:18 +02008443/* Connect Line-Out side jack (SPDIF) to Side */
8444 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8445 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8446 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
8447/* Connect Mic jack to CLFE */
8448 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8449 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8450 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
8451/* Connect Line-in jack to Surround */
8452 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8453 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8454 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
8455/* Connect HP out jack to Front */
8456 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8457 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8458 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangccc656c2006-10-17 12:32:26 +02008459
8460 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangccc656c2006-10-17 12:32:26 +02008461
8462 { } /* end */
8463};
8464
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008465static struct hda_verb alc883_lenovo_101e_verbs[] = {
8466 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8467 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
8468 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
8469 { } /* end */
8470};
8471
Kailang Yang272a5272007-05-14 11:00:38 +02008472static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
8473 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8474 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8475 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8476 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8477 { } /* end */
8478};
8479
8480static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
8481 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8482 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8483 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8484 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
8485 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8486 { } /* end */
8487};
8488
Kailang Yang189609a2007-08-20 11:31:23 +02008489static struct hda_verb alc883_haier_w66_verbs[] = {
8490 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8491 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8492
8493 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8494
8495 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8496 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8497 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8498 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8499 { } /* end */
8500};
8501
Kailang Yange2757d52008-08-26 13:17:46 +02008502static struct hda_verb alc888_lenovo_sky_verbs[] = {
8503 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8504 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8505 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8506 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8507 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8508 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8509 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8510 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8511 { } /* end */
8512};
8513
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008514static struct hda_verb alc888_6st_dell_verbs[] = {
8515 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8516 { }
8517};
8518
Guido Günther3e1647c2009-06-05 00:47:26 +02008519static struct hda_verb alc883_vaiott_verbs[] = {
8520 /* HP */
8521 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8522 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8523
8524 /* enable unsolicited event */
8525 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8526
8527 { } /* end */
8528};
8529
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008530static void alc888_3st_hp_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008531{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008532 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008533
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008534 spec->autocfg.hp_pins[0] = 0x1b;
8535 spec->autocfg.speaker_pins[0] = 0x14;
8536 spec->autocfg.speaker_pins[1] = 0x16;
8537 spec->autocfg.speaker_pins[2] = 0x18;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008538}
8539
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008540static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008541 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01008542 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
8543 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008544 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008545 { } /* end */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008546};
8547
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008548/*
8549 * 2ch mode
8550 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008551static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008552 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
8553 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8554 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
8555 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008556 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008557};
8558
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008559/*
8560 * 4ch mode
8561 */
8562static struct hda_verb alc888_3st_hp_4ch_init[] = {
8563 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
8564 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8565 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8566 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8567 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
8568 { } /* end */
8569};
8570
8571/*
8572 * 6ch mode
8573 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008574static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008575 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8576 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008577 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008578 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8579 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008580 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
8581 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008582};
8583
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008584static struct hda_channel_mode alc888_3st_hp_modes[3] = {
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008585 { 2, alc888_3st_hp_2ch_init },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008586 { 4, alc888_3st_hp_4ch_init },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008587 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008588};
8589
Kailang Yang272a5272007-05-14 11:00:38 +02008590/* toggle front-jack and RCA according to the hp-jack state */
8591static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
8592{
Wu Fengguang864f92b2009-11-18 12:38:02 +08008593 unsigned int present = snd_hda_jack_detect(codec, 0x1b);
Kailang Yangea1fb292008-08-26 12:58:38 +02008594
Takashi Iwai47fd8302007-08-10 17:11:07 +02008595 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8596 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8597 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8598 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02008599}
8600
8601/* toggle RCA according to the front-jack state */
8602static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
8603{
Wu Fengguang864f92b2009-11-18 12:38:02 +08008604 unsigned int present = snd_hda_jack_detect(codec, 0x14);
Kailang Yangea1fb292008-08-26 12:58:38 +02008605
Takashi Iwai47fd8302007-08-10 17:11:07 +02008606 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8607 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02008608}
Takashi Iwai47fd8302007-08-10 17:11:07 +02008609
Kailang Yang272a5272007-05-14 11:00:38 +02008610static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
8611 unsigned int res)
8612{
8613 if ((res >> 26) == ALC880_HP_EVENT)
8614 alc888_lenovo_ms7195_front_automute(codec);
8615 if ((res >> 26) == ALC880_FRONT_EVENT)
8616 alc888_lenovo_ms7195_rca_automute(codec);
8617}
8618
8619static struct hda_verb alc883_medion_md2_verbs[] = {
8620 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8621 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8622
8623 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8624
8625 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8626 { } /* end */
8627};
8628
8629/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008630static void alc883_medion_md2_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +02008631{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008632 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02008633
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008634 spec->autocfg.hp_pins[0] = 0x14;
8635 spec->autocfg.speaker_pins[0] = 0x15;
Kailang Yang272a5272007-05-14 11:00:38 +02008636}
8637
Kailang Yangccc656c2006-10-17 12:32:26 +02008638/* toggle speaker-output according to the hp-jack state */
Sasha Alexandrc2592492009-06-16 14:52:54 -04008639#define alc883_targa_init_hook alc882_targa_init_hook
8640#define alc883_targa_unsol_event alc882_targa_unsol_event
Jiang zhe368c7a92008-03-04 11:20:33 +01008641
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008642static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
8643{
8644 unsigned int present;
8645
Takashi Iwaid56757a2009-11-18 08:00:14 +01008646 present = snd_hda_jack_detect(codec, 0x18);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008647 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
8648 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8649}
8650
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008651static void alc883_clevo_m720_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008652{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008653 struct alc_spec *spec = codec->spec;
8654
8655 spec->autocfg.hp_pins[0] = 0x15;
8656 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008657}
8658
8659static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
8660{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008661 alc_automute_amp(codec);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008662 alc883_clevo_m720_mic_automute(codec);
8663}
8664
8665static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01008666 unsigned int res)
8667{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008668 switch (res >> 26) {
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008669 case ALC880_MIC_EVENT:
8670 alc883_clevo_m720_mic_automute(codec);
8671 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008672 default:
8673 alc_automute_amp_unsol_event(codec, res);
8674 break;
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008675 }
Jiang zhe368c7a92008-03-04 11:20:33 +01008676}
8677
Jiang zhefb97dc62008-03-06 11:07:11 +01008678/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008679static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01008680{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008681 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01008682
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008683 spec->autocfg.hp_pins[0] = 0x14;
8684 spec->autocfg.speaker_pins[0] = 0x15;
Jiang zhefb97dc62008-03-06 11:07:11 +01008685}
8686
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008687static void alc883_haier_w66_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01008688{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008689 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01008690
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008691 spec->autocfg.hp_pins[0] = 0x1b;
8692 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang189609a2007-08-20 11:31:23 +02008693}
8694
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008695static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
8696{
Wu Fengguang864f92b2009-11-18 12:38:02 +08008697 int bits = snd_hda_jack_detect(codec, 0x14) ? HDA_AMP_MUTE : 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008698
Takashi Iwai47fd8302007-08-10 17:11:07 +02008699 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8700 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008701}
8702
8703static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
8704{
Wu Fengguang864f92b2009-11-18 12:38:02 +08008705 int bits = snd_hda_jack_detect(codec, 0x1b) ? HDA_AMP_MUTE : 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008706
Takashi Iwai47fd8302007-08-10 17:11:07 +02008707 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8708 HDA_AMP_MUTE, bits);
8709 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8710 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008711}
8712
8713static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
8714 unsigned int res)
8715{
8716 if ((res >> 26) == ALC880_HP_EVENT)
8717 alc883_lenovo_101e_all_automute(codec);
8718 if ((res >> 26) == ALC880_FRONT_EVENT)
8719 alc883_lenovo_101e_ispeaker_automute(codec);
8720}
8721
Takashi Iwai676a9b52007-08-16 15:23:35 +02008722/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008723static void alc883_acer_aspire_setup(struct hda_codec *codec)
Takashi Iwai676a9b52007-08-16 15:23:35 +02008724{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008725 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02008726
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008727 spec->autocfg.hp_pins[0] = 0x14;
8728 spec->autocfg.speaker_pins[0] = 0x15;
8729 spec->autocfg.speaker_pins[1] = 0x16;
Takashi Iwai676a9b52007-08-16 15:23:35 +02008730}
8731
Kailang Yangd1a991a2007-08-15 16:21:59 +02008732static struct hda_verb alc883_acer_eapd_verbs[] = {
8733 /* HP Pin: output 0 (0x0c) */
8734 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8735 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8736 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8737 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02008738 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8739 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02008740 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02008741 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
8742 /* eanable EAPD on medion laptop */
8743 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8744 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02008745 /* enable unsolicited event */
8746 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02008747 { }
8748};
8749
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02008750static struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
8751 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8752 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
8753 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8754 { } /* end */
8755};
8756
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008757static void alc888_6st_dell_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008758{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008759 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02008760
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008761 spec->autocfg.hp_pins[0] = 0x1b;
8762 spec->autocfg.speaker_pins[0] = 0x14;
8763 spec->autocfg.speaker_pins[1] = 0x15;
8764 spec->autocfg.speaker_pins[2] = 0x16;
8765 spec->autocfg.speaker_pins[3] = 0x17;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008766}
8767
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008768static void alc888_lenovo_sky_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008769{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008770 struct alc_spec *spec = codec->spec;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008771
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008772 spec->autocfg.hp_pins[0] = 0x1b;
8773 spec->autocfg.speaker_pins[0] = 0x14;
8774 spec->autocfg.speaker_pins[1] = 0x15;
8775 spec->autocfg.speaker_pins[2] = 0x16;
8776 spec->autocfg.speaker_pins[3] = 0x17;
8777 spec->autocfg.speaker_pins[4] = 0x1a;
Kailang Yange2757d52008-08-26 13:17:46 +02008778}
8779
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008780static void alc883_vaiott_setup(struct hda_codec *codec)
Guido Günther3e1647c2009-06-05 00:47:26 +02008781{
8782 struct alc_spec *spec = codec->spec;
8783
8784 spec->autocfg.hp_pins[0] = 0x15;
8785 spec->autocfg.speaker_pins[0] = 0x14;
8786 spec->autocfg.speaker_pins[1] = 0x17;
Guido Günther3e1647c2009-06-05 00:47:26 +02008787}
8788
Kailang Yange2757d52008-08-26 13:17:46 +02008789static struct hda_verb alc888_asus_m90v_verbs[] = {
8790 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8791 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8792 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8793 /* enable unsolicited event */
8794 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8795 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
8796 { } /* end */
8797};
8798
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008799static void alc883_mode2_setup(struct hda_codec *codec)
Kailang Yange2757d52008-08-26 13:17:46 +02008800{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008801 struct alc_spec *spec = codec->spec;
Kailang Yange2757d52008-08-26 13:17:46 +02008802
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008803 spec->autocfg.hp_pins[0] = 0x1b;
8804 spec->autocfg.speaker_pins[0] = 0x14;
8805 spec->autocfg.speaker_pins[1] = 0x15;
8806 spec->autocfg.speaker_pins[2] = 0x16;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008807 spec->ext_mic.pin = 0x18;
8808 spec->int_mic.pin = 0x19;
8809 spec->ext_mic.mux_idx = 0;
8810 spec->int_mic.mux_idx = 1;
8811 spec->auto_mic = 1;
Kailang Yange2757d52008-08-26 13:17:46 +02008812}
8813
8814static struct hda_verb alc888_asus_eee1601_verbs[] = {
8815 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8816 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8817 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8818 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8819 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8820 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
8821 {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
8822 /* enable unsolicited event */
8823 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8824 { } /* end */
8825};
8826
Kailang Yange2757d52008-08-26 13:17:46 +02008827static void alc883_eee1601_inithook(struct hda_codec *codec)
8828{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008829 struct alc_spec *spec = codec->spec;
8830
8831 spec->autocfg.hp_pins[0] = 0x14;
8832 spec->autocfg.speaker_pins[0] = 0x1b;
8833 alc_automute_pin(codec);
Kailang Yange2757d52008-08-26 13:17:46 +02008834}
8835
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008836static struct hda_verb alc889A_mb31_verbs[] = {
8837 /* Init rear pin (used as headphone output) */
8838 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */
8839 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */
8840 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8841 /* Init line pin (used as output in 4ch and 6ch mode) */
8842 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Connect to CLFE */
8843 /* Init line 2 pin (used as headphone out by default) */
8844 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Use as input */
8845 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */
8846 { } /* end */
8847};
8848
8849/* Mute speakers according to the headphone jack state */
8850static void alc889A_mb31_automute(struct hda_codec *codec)
8851{
8852 unsigned int present;
8853
8854 /* Mute only in 2ch or 4ch mode */
8855 if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0)
8856 == 0x00) {
Wu Fengguang864f92b2009-11-18 12:38:02 +08008857 present = snd_hda_jack_detect(codec, 0x15);
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008858 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8859 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8860 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8861 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8862 }
8863}
8864
8865static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
8866{
8867 if ((res >> 26) == ALC880_HP_EVENT)
8868 alc889A_mb31_automute(codec);
8869}
8870
Takashi Iwai49535502009-06-30 15:28:30 +02008871
Takashi Iwaicb53c622007-08-10 17:21:45 +02008872#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwai49535502009-06-30 15:28:30 +02008873#define alc882_loopbacks alc880_loopbacks
Takashi Iwaicb53c622007-08-10 17:21:45 +02008874#endif
8875
Sasha Alexandrdef319f2009-06-16 16:00:15 -04008876/* pcm configuration: identical with ALC880 */
Takashi Iwai49535502009-06-30 15:28:30 +02008877#define alc882_pcm_analog_playback alc880_pcm_analog_playback
8878#define alc882_pcm_analog_capture alc880_pcm_analog_capture
8879#define alc882_pcm_digital_playback alc880_pcm_digital_playback
8880#define alc882_pcm_digital_capture alc880_pcm_digital_capture
8881
8882static hda_nid_t alc883_slave_dig_outs[] = {
8883 ALC1200_DIGOUT_NID, 0,
8884};
8885
8886static hda_nid_t alc1200_slave_dig_outs[] = {
8887 ALC883_DIGOUT_NID, 0,
8888};
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008889
8890/*
8891 * configuration and preset
8892 */
Takashi Iwai49535502009-06-30 15:28:30 +02008893static const char *alc882_models[ALC882_MODEL_LAST] = {
8894 [ALC882_3ST_DIG] = "3stack-dig",
8895 [ALC882_6ST_DIG] = "6stack-dig",
8896 [ALC882_ARIMA] = "arima",
8897 [ALC882_W2JC] = "w2jc",
8898 [ALC882_TARGA] = "targa",
8899 [ALC882_ASUS_A7J] = "asus-a7j",
8900 [ALC882_ASUS_A7M] = "asus-a7m",
8901 [ALC885_MACPRO] = "macpro",
8902 [ALC885_MB5] = "mb5",
8903 [ALC885_MBP3] = "mbp3",
8904 [ALC885_IMAC24] = "imac24",
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008905 [ALC885_IMAC91] = "imac91",
Takashi Iwai49535502009-06-30 15:28:30 +02008906 [ALC883_3ST_2ch_DIG] = "3stack-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008907 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
8908 [ALC883_3ST_6ch] = "3stack-6ch",
Takashi Iwai49535502009-06-30 15:28:30 +02008909 [ALC883_6ST_DIG] = "alc883-6stack-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008910 [ALC883_TARGA_DIG] = "targa-dig",
8911 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
David Heidelberger64a8be72009-06-08 16:15:18 +02008912 [ALC883_TARGA_8ch_DIG] = "targa-8ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008913 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02008914 [ALC883_ACER_ASPIRE] = "acer-aspire",
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08008915 [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g",
Takashi Iwaib1a91462009-06-21 10:56:44 +02008916 [ALC888_ACER_ASPIRE_6530G] = "acer-aspire-6530g",
Hector Martin3b315d72009-06-02 10:54:19 +02008917 [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g",
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02008918 [ALC888_ACER_ASPIRE_7730G] = "acer-aspire-7730g",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008919 [ALC883_MEDION] = "medion",
Kailang Yang272a5272007-05-14 11:00:38 +02008920 [ALC883_MEDION_MD2] = "medion-md2",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008921 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008922 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02008923 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
8924 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yange2757d52008-08-26 13:17:46 +02008925 [ALC888_LENOVO_SKY] = "lenovo-sky",
Kailang Yang189609a2007-08-20 11:31:23 +02008926 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008927 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008928 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008929 [ALC883_MITAC] = "mitac",
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04308930 [ALC883_CLEVO_M540R] = "clevo-m540r",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008931 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +01008932 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08008933 [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
Jiang zhe17bba1b2008-06-04 12:11:07 +02008934 [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008935 [ALC889A_INTEL] = "intel-alc889a",
8936 [ALC889_INTEL] = "intel-x58",
Wu Fengguang3ab90932008-11-17 09:51:09 +01008937 [ALC1200_ASUS_P5Q] = "asus-p5q",
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008938 [ALC889A_MB31] = "mb31",
Guido Günther3e1647c2009-06-05 00:47:26 +02008939 [ALC883_SONY_VAIO_TT] = "sony-vaio-tt",
Takashi Iwai49535502009-06-30 15:28:30 +02008940 [ALC882_AUTO] = "auto",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008941};
8942
Takashi Iwai49535502009-06-30 15:28:30 +02008943static struct snd_pci_quirk alc882_cfg_tbl[] = {
8944 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
8945
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008946 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
Takashi Iwai69e50282008-11-03 10:07:43 +01008947 SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
Takashi Iwai9b6682f2009-03-23 22:50:52 +01008948 SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008949 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
8950 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
Jaroslav Kysela0b18cb12008-07-28 17:07:07 +02008951 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08008952 SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
8953 ALC888_ACER_ASPIRE_4930G),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01008954 SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
Takashi Iwai83dd7402009-11-24 08:57:53 +01008955 ALC888_ACER_ASPIRE_4930G),
Hector Martin3b315d72009-06-02 10:54:19 +02008956 SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
8957 ALC888_ACER_ASPIRE_8930G),
Takashi Iwaie46b0c82009-06-13 10:16:43 +02008958 SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
8959 ALC888_ACER_ASPIRE_8930G),
Takashi Iwai49535502009-06-30 15:28:30 +02008960 SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO),
8961 SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01008962 SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
Takashi Iwaidde65352009-06-25 08:25:35 +02008963 ALC888_ACER_ASPIRE_6530G),
Juan Jesus Garcia de Soriacc374c42009-02-23 08:11:59 +01008964 SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
Tony Vroond2fd4b02009-06-21 00:40:10 +01008965 ALC888_ACER_ASPIRE_6530G),
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02008966 SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
8967 ALC888_ACER_ASPIRE_7730G),
Takashi Iwai22b530e2009-05-13 11:32:52 +02008968 /* default Acer -- disabled as it causes more problems.
8969 * model=auto should work fine now
8970 */
8971 /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */
Takashi Iwai49535502009-06-30 15:28:30 +02008972
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008973 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Takashi Iwai49535502009-06-30 15:28:30 +02008974
Tobin Davisfebe3372007-06-12 11:27:46 +02008975 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008976 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
8977 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +01008978 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Chris Bagwell06bf3e12009-01-01 10:32:08 +01008979 SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
Herton Ronaldo Krzesinski7ec30f02009-03-04 14:22:52 -03008980 SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
Takashi Iwai49535502009-06-30 15:28:30 +02008981
8982 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
8983 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
8984 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Kailang Yanga01c30c2008-10-15 11:14:58 +02008985 SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
Takashi Iwai49535502009-06-30 15:28:30 +02008986 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
8987 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
8988 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008989 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Mackenzie Morgan44a678d2009-02-10 17:13:43 +01008990 SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
Wu Fengguang3ab90932008-11-17 09:51:09 +01008991 SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
Kailang Yange2757d52008-08-26 13:17:46 +02008992 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
Takashi Iwai49535502009-06-30 15:28:30 +02008993
8994 SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
Travis Place97ec7102008-05-23 18:31:46 +02008995 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02008996 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Luke Yelavich2de686d2009-01-16 15:08:02 +11008997 SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008998 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
8999 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
Kailang Yange2757d52008-08-26 13:17:46 +02009000 SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009001 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Takashi Iwai49535502009-06-30 15:28:30 +02009002 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
9003
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009004 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
9005 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
9006 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009007 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
Jiang zhe4383fae2008-04-14 12:58:57 +02009008 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009009 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009010 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01009011 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009012 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
9013 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
9014 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
9015 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
9016 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
9017 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009018 SND_PCI_QUIRK(0x1462, 0x42cd, "MSI", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009019 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
9020 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
9021 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
David Heidelberger64a8be72009-06-08 16:15:18 +02009022 SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009023 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
9024 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02009025 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Takashi Iwaiee095432008-11-25 15:03:38 +01009026 SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +01009027 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01009028 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02009029 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Sasha Alexandrdf01b8a2009-06-16 14:46:17 -04009030 SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009031 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009032 SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009033
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009034 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009035 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
9036 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309037 SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R),
Takashi Iwaidea0a502009-02-09 17:14:52 +01009038 SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04009039 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwai49535502009-06-30 15:28:30 +02009040 /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009041 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009042 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
Takashi Iwaif67d8172009-02-04 23:30:19 +01009043 ALC883_FUJITSU_PI2515),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009044 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009045 ALC888_FUJITSU_XA3530),
Kailang Yang272a5272007-05-14 11:00:38 +02009046 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02009047 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009048 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
9049 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yange2757d52008-08-26 13:17:46 +02009050 SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
Kailang Yang272a5272007-05-14 11:00:38 +02009051 SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
Takashi Iwai959973b2008-11-05 11:30:56 +01009052 SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01009053 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02009054 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Takashi Iwai49535502009-06-30 15:28:30 +02009055
Jiang zhe17bba1b2008-06-04 12:11:07 +02009056 SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
9057 SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009058 SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009059 SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL),
9060 SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL),
9061 SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009062 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
Takashi Iwai49535502009-06-30 15:28:30 +02009063
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009064 {}
9065};
9066
Takashi Iwai49535502009-06-30 15:28:30 +02009067/* codec SSID table for Intel Mac */
9068static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
9069 SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3),
9070 SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3),
9071 SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3),
9072 SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO),
9073 SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24),
9074 SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24),
9075 SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3),
9076 SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
9077 SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
9078 SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009079 SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91),
Takashi Iwai49535502009-06-30 15:28:30 +02009080 SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -05009081 /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2,
9082 * so apparently no perfect solution yet
Takashi Iwai49535502009-06-30 15:28:30 +02009083 */
9084 SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -05009085 SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5),
Takashi Iwai49535502009-06-30 15:28:30 +02009086 {} /* terminator */
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08009087};
9088
Takashi Iwai49535502009-06-30 15:28:30 +02009089static struct alc_config_preset alc882_presets[] = {
9090 [ALC882_3ST_DIG] = {
9091 .mixers = { alc882_base_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009092 .init_verbs = { alc882_base_init_verbs,
9093 alc882_adc1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +02009094 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9095 .dac_nids = alc882_dac_nids,
9096 .dig_out_nid = ALC882_DIGOUT_NID,
9097 .dig_in_nid = ALC882_DIGIN_NID,
9098 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
9099 .channel_mode = alc882_ch_modes,
9100 .need_dac_fix = 1,
9101 .input_mux = &alc882_capture_source,
9102 },
9103 [ALC882_6ST_DIG] = {
9104 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009105 .init_verbs = { alc882_base_init_verbs,
9106 alc882_adc1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +02009107 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9108 .dac_nids = alc882_dac_nids,
9109 .dig_out_nid = ALC882_DIGOUT_NID,
9110 .dig_in_nid = ALC882_DIGIN_NID,
9111 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
9112 .channel_mode = alc882_sixstack_modes,
9113 .input_mux = &alc882_capture_source,
9114 },
9115 [ALC882_ARIMA] = {
9116 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009117 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9118 alc882_eapd_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +02009119 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9120 .dac_nids = alc882_dac_nids,
9121 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
9122 .channel_mode = alc882_sixstack_modes,
9123 .input_mux = &alc882_capture_source,
9124 },
9125 [ALC882_W2JC] = {
9126 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009127 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9128 alc882_eapd_verbs, alc880_gpio1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +02009129 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9130 .dac_nids = alc882_dac_nids,
9131 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
9132 .channel_mode = alc880_threestack_modes,
9133 .need_dac_fix = 1,
9134 .input_mux = &alc882_capture_source,
9135 .dig_out_nid = ALC882_DIGOUT_NID,
9136 },
9137 [ALC885_MBP3] = {
9138 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
9139 .init_verbs = { alc885_mbp3_init_verbs,
9140 alc880_gpio1_init_verbs },
Takashi Iwaibe0ae922009-08-31 08:27:10 +02009141 .num_dacs = 2,
Takashi Iwai49535502009-06-30 15:28:30 +02009142 .dac_nids = alc882_dac_nids,
Takashi Iwaibe0ae922009-08-31 08:27:10 +02009143 .hp_nid = 0x04,
9144 .channel_mode = alc885_mbp_4ch_modes,
9145 .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes),
Takashi Iwai49535502009-06-30 15:28:30 +02009146 .input_mux = &alc882_capture_source,
9147 .dig_out_nid = ALC882_DIGOUT_NID,
9148 .dig_in_nid = ALC882_DIGIN_NID,
9149 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009150 .setup = alc885_mbp3_setup,
9151 .init_hook = alc_automute_amp,
Takashi Iwai49535502009-06-30 15:28:30 +02009152 },
9153 [ALC885_MB5] = {
9154 .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
9155 .init_verbs = { alc885_mb5_init_verbs,
9156 alc880_gpio1_init_verbs },
9157 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9158 .dac_nids = alc882_dac_nids,
9159 .channel_mode = alc885_mb5_6ch_modes,
9160 .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
9161 .input_mux = &mb5_capture_source,
9162 .dig_out_nid = ALC882_DIGOUT_NID,
9163 .dig_in_nid = ALC882_DIGIN_NID,
9164 },
9165 [ALC885_MACPRO] = {
9166 .mixers = { alc882_macpro_mixer },
9167 .init_verbs = { alc882_macpro_init_verbs },
9168 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9169 .dac_nids = alc882_dac_nids,
9170 .dig_out_nid = ALC882_DIGOUT_NID,
9171 .dig_in_nid = ALC882_DIGIN_NID,
9172 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
9173 .channel_mode = alc882_ch_modes,
9174 .input_mux = &alc882_capture_source,
9175 .init_hook = alc885_macpro_init_hook,
9176 },
9177 [ALC885_IMAC24] = {
9178 .mixers = { alc885_imac24_mixer },
9179 .init_verbs = { alc885_imac24_init_verbs },
9180 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9181 .dac_nids = alc882_dac_nids,
9182 .dig_out_nid = ALC882_DIGOUT_NID,
9183 .dig_in_nid = ALC882_DIGIN_NID,
9184 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
9185 .channel_mode = alc882_ch_modes,
9186 .input_mux = &alc882_capture_source,
9187 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009188 .setup = alc885_imac24_setup,
Takashi Iwai49535502009-06-30 15:28:30 +02009189 .init_hook = alc885_imac24_init_hook,
9190 },
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009191 [ALC885_IMAC91] = {
9192 .mixers = { alc885_imac91_mixer, alc882_chmode_mixer },
9193 .init_verbs = { alc885_imac91_init_verbs,
9194 alc880_gpio1_init_verbs },
9195 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9196 .dac_nids = alc882_dac_nids,
9197 .channel_mode = alc885_mbp_4ch_modes,
9198 .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes),
9199 .input_mux = &alc882_capture_source,
9200 .dig_out_nid = ALC882_DIGOUT_NID,
9201 .dig_in_nid = ALC882_DIGIN_NID,
9202 .unsol_event = alc885_imac91_unsol_event,
9203 .init_hook = alc885_imac91_automute,
9204 },
Takashi Iwai49535502009-06-30 15:28:30 +02009205 [ALC882_TARGA] = {
9206 .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009207 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
Takashi Iwai31909b82009-07-10 12:33:48 +02009208 alc880_gpio3_init_verbs, alc882_targa_verbs},
Takashi Iwai49535502009-06-30 15:28:30 +02009209 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9210 .dac_nids = alc882_dac_nids,
9211 .dig_out_nid = ALC882_DIGOUT_NID,
9212 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
9213 .adc_nids = alc882_adc_nids,
9214 .capsrc_nids = alc882_capsrc_nids,
9215 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
9216 .channel_mode = alc882_3ST_6ch_modes,
9217 .need_dac_fix = 1,
9218 .input_mux = &alc882_capture_source,
9219 .unsol_event = alc882_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009220 .setup = alc882_targa_setup,
9221 .init_hook = alc882_targa_automute,
Takashi Iwai49535502009-06-30 15:28:30 +02009222 },
9223 [ALC882_ASUS_A7J] = {
9224 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009225 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9226 alc882_asus_a7j_verbs},
Takashi Iwai49535502009-06-30 15:28:30 +02009227 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9228 .dac_nids = alc882_dac_nids,
9229 .dig_out_nid = ALC882_DIGOUT_NID,
9230 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
9231 .adc_nids = alc882_adc_nids,
9232 .capsrc_nids = alc882_capsrc_nids,
9233 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
9234 .channel_mode = alc882_3ST_6ch_modes,
9235 .need_dac_fix = 1,
9236 .input_mux = &alc882_capture_source,
9237 },
9238 [ALC882_ASUS_A7M] = {
9239 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009240 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9241 alc882_eapd_verbs, alc880_gpio1_init_verbs,
Takashi Iwai49535502009-06-30 15:28:30 +02009242 alc882_asus_a7m_verbs },
9243 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9244 .dac_nids = alc882_dac_nids,
9245 .dig_out_nid = ALC882_DIGOUT_NID,
9246 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
9247 .channel_mode = alc880_threestack_modes,
9248 .need_dac_fix = 1,
9249 .input_mux = &alc882_capture_source,
9250 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009251 [ALC883_3ST_2ch_DIG] = {
9252 .mixers = { alc883_3ST_2ch_mixer },
9253 .init_verbs = { alc883_init_verbs },
9254 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9255 .dac_nids = alc883_dac_nids,
9256 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009257 .dig_in_nid = ALC883_DIGIN_NID,
9258 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9259 .channel_mode = alc883_3ST_2ch_modes,
9260 .input_mux = &alc883_capture_source,
9261 },
9262 [ALC883_3ST_6ch_DIG] = {
9263 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9264 .init_verbs = { alc883_init_verbs },
9265 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9266 .dac_nids = alc883_dac_nids,
9267 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009268 .dig_in_nid = ALC883_DIGIN_NID,
9269 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9270 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02009271 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009272 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009273 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009274 [ALC883_3ST_6ch] = {
9275 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9276 .init_verbs = { alc883_init_verbs },
9277 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9278 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009279 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9280 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02009281 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009282 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009283 },
Jiang zhe17bba1b2008-06-04 12:11:07 +02009284 [ALC883_3ST_6ch_INTEL] = {
9285 .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
9286 .init_verbs = { alc883_init_verbs },
9287 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9288 .dac_nids = alc883_dac_nids,
9289 .dig_out_nid = ALC883_DIGOUT_NID,
9290 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08009291 .slave_dig_outs = alc883_slave_dig_outs,
Jiang zhe17bba1b2008-06-04 12:11:07 +02009292 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
9293 .channel_mode = alc883_3ST_6ch_intel_modes,
9294 .need_dac_fix = 1,
9295 .input_mux = &alc883_3stack_6ch_intel,
9296 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009297 [ALC889A_INTEL] = {
9298 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +02009299 .init_verbs = { alc885_init_verbs, alc885_init_input_verbs,
9300 alc_hp15_unsol_verbs },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009301 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9302 .dac_nids = alc883_dac_nids,
9303 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
9304 .adc_nids = alc889_adc_nids,
9305 .dig_out_nid = ALC883_DIGOUT_NID,
9306 .dig_in_nid = ALC883_DIGIN_NID,
9307 .slave_dig_outs = alc883_slave_dig_outs,
9308 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
9309 .channel_mode = alc889_8ch_intel_modes,
9310 .capsrc_nids = alc889_capsrc_nids,
9311 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009312 .setup = alc889_automute_setup,
9313 .init_hook = alc_automute_amp,
Wu Fengguang6732bd02009-07-30 09:19:14 +02009314 .unsol_event = alc_automute_amp_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009315 .need_dac_fix = 1,
9316 },
9317 [ALC889_INTEL] = {
9318 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
9319 .init_verbs = { alc885_init_verbs, alc889_init_input_verbs,
Wu Fengguang6732bd02009-07-30 09:19:14 +02009320 alc889_eapd_verbs, alc_hp15_unsol_verbs},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009321 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9322 .dac_nids = alc883_dac_nids,
9323 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
9324 .adc_nids = alc889_adc_nids,
9325 .dig_out_nid = ALC883_DIGOUT_NID,
9326 .dig_in_nid = ALC883_DIGIN_NID,
9327 .slave_dig_outs = alc883_slave_dig_outs,
9328 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
9329 .channel_mode = alc889_8ch_intel_modes,
9330 .capsrc_nids = alc889_capsrc_nids,
9331 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009332 .setup = alc889_automute_setup,
Wu Fengguang6732bd02009-07-30 09:19:14 +02009333 .init_hook = alc889_intel_init_hook,
9334 .unsol_event = alc_automute_amp_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009335 .need_dac_fix = 1,
9336 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009337 [ALC883_6ST_DIG] = {
9338 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
9339 .init_verbs = { alc883_init_verbs },
9340 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9341 .dac_nids = alc883_dac_nids,
9342 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009343 .dig_in_nid = ALC883_DIGIN_NID,
9344 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9345 .channel_mode = alc883_sixstack_modes,
9346 .input_mux = &alc883_capture_source,
9347 },
Kailang Yangccc656c2006-10-17 12:32:26 +02009348 [ALC883_TARGA_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -04009349 .mixers = { alc883_targa_mixer, alc883_chmode_mixer },
David Heidelberger005b1072009-07-09 18:45:46 +02009350 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
9351 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +02009352 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9353 .dac_nids = alc883_dac_nids,
9354 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02009355 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9356 .channel_mode = alc883_3ST_6ch_modes,
9357 .need_dac_fix = 1,
9358 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -04009359 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009360 .setup = alc882_targa_setup,
9361 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02009362 },
9363 [ALC883_TARGA_2ch_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -04009364 .mixers = { alc883_targa_2ch_mixer},
David Heidelberger005b1072009-07-09 18:45:46 +02009365 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
9366 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +02009367 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9368 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009369 .adc_nids = alc883_adc_nids_alt,
9370 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Kailang Yangccc656c2006-10-17 12:32:26 +02009371 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02009372 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9373 .channel_mode = alc883_3ST_2ch_modes,
9374 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -04009375 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009376 .setup = alc882_targa_setup,
9377 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02009378 },
David Heidelberger64a8be72009-06-08 16:15:18 +02009379 [ALC883_TARGA_8ch_DIG] = {
Takashi Iwaib99dba32009-09-17 18:23:00 +02009380 .mixers = { alc883_targa_mixer, alc883_targa_8ch_mixer,
9381 alc883_chmode_mixer },
David Heidelberger64a8be72009-06-08 16:15:18 +02009382 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
Sasha Alexandrc2592492009-06-16 14:52:54 -04009383 alc883_targa_verbs },
David Heidelberger64a8be72009-06-08 16:15:18 +02009384 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9385 .dac_nids = alc883_dac_nids,
9386 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
9387 .adc_nids = alc883_adc_nids_rev,
9388 .capsrc_nids = alc883_capsrc_nids_rev,
9389 .dig_out_nid = ALC883_DIGOUT_NID,
9390 .dig_in_nid = ALC883_DIGIN_NID,
9391 .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes),
9392 .channel_mode = alc883_4ST_8ch_modes,
9393 .need_dac_fix = 1,
9394 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -04009395 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009396 .setup = alc882_targa_setup,
9397 .init_hook = alc882_targa_automute,
David Heidelberger64a8be72009-06-08 16:15:18 +02009398 },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02009399 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02009400 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02009401 /* On TravelMate laptops, GPIO 0 enables the internal speaker
9402 * and the headphone jack. Turn this on and rely on the
9403 * standard mute methods whenever the user wants to turn
9404 * these outputs off.
9405 */
9406 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
9407 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9408 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02009409 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9410 .channel_mode = alc883_3ST_2ch_modes,
9411 .input_mux = &alc883_capture_source,
9412 },
Tobin Davis2880a862007-08-07 11:50:26 +02009413 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02009414 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +02009415 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +02009416 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9417 .dac_nids = alc883_dac_nids,
9418 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +02009419 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9420 .channel_mode = alc883_3ST_2ch_modes,
9421 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009422 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009423 .setup = alc883_acer_aspire_setup,
9424 .init_hook = alc_automute_amp,
Kailang Yangd1a991a2007-08-15 16:21:59 +02009425 },
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009426 [ALC888_ACER_ASPIRE_4930G] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009427 .mixers = { alc888_base_mixer,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009428 alc883_chmode_mixer },
9429 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
9430 alc888_acer_aspire_4930g_verbs },
9431 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9432 .dac_nids = alc883_dac_nids,
9433 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
9434 .adc_nids = alc883_adc_nids_rev,
9435 .capsrc_nids = alc883_capsrc_nids_rev,
9436 .dig_out_nid = ALC883_DIGOUT_NID,
9437 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9438 .channel_mode = alc883_3ST_6ch_modes,
9439 .need_dac_fix = 1,
9440 .num_mux_defs =
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009441 ARRAY_SIZE(alc888_2_capture_sources),
9442 .input_mux = alc888_2_capture_sources,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009443 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009444 .setup = alc888_acer_aspire_4930g_setup,
9445 .init_hook = alc_automute_amp,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009446 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01009447 [ALC888_ACER_ASPIRE_6530G] = {
9448 .mixers = { alc888_acer_aspire_6530_mixer },
9449 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
9450 alc888_acer_aspire_6530g_verbs },
9451 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9452 .dac_nids = alc883_dac_nids,
9453 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
9454 .adc_nids = alc883_adc_nids_rev,
9455 .capsrc_nids = alc883_capsrc_nids_rev,
9456 .dig_out_nid = ALC883_DIGOUT_NID,
9457 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9458 .channel_mode = alc883_3ST_2ch_modes,
9459 .num_mux_defs =
9460 ARRAY_SIZE(alc888_2_capture_sources),
9461 .input_mux = alc888_acer_aspire_6530_sources,
9462 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009463 .setup = alc888_acer_aspire_6530g_setup,
9464 .init_hook = alc_automute_amp,
Tony Vroond2fd4b02009-06-21 00:40:10 +01009465 },
Hector Martin3b315d72009-06-02 10:54:19 +02009466 [ALC888_ACER_ASPIRE_8930G] = {
9467 .mixers = { alc888_base_mixer,
9468 alc883_chmode_mixer },
9469 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
Hector Martin018df412009-06-04 00:13:40 +02009470 alc889_acer_aspire_8930g_verbs },
Hector Martin3b315d72009-06-02 10:54:19 +02009471 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9472 .dac_nids = alc883_dac_nids,
Hector Martin018df412009-06-04 00:13:40 +02009473 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
9474 .adc_nids = alc889_adc_nids,
9475 .capsrc_nids = alc889_capsrc_nids,
Hector Martin3b315d72009-06-02 10:54:19 +02009476 .dig_out_nid = ALC883_DIGOUT_NID,
9477 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9478 .channel_mode = alc883_3ST_6ch_modes,
9479 .need_dac_fix = 1,
9480 .const_channel_count = 6,
9481 .num_mux_defs =
Hector Martin018df412009-06-04 00:13:40 +02009482 ARRAY_SIZE(alc889_capture_sources),
9483 .input_mux = alc889_capture_sources,
Hector Martin3b315d72009-06-02 10:54:19 +02009484 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009485 .setup = alc889_acer_aspire_8930g_setup,
9486 .init_hook = alc_automute_amp,
Hector Martin3b315d72009-06-02 10:54:19 +02009487 },
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009488 [ALC888_ACER_ASPIRE_7730G] = {
9489 .mixers = { alc883_3ST_6ch_mixer,
9490 alc883_chmode_mixer },
9491 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
9492 alc888_acer_aspire_7730G_verbs },
9493 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9494 .dac_nids = alc883_dac_nids,
9495 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
9496 .adc_nids = alc883_adc_nids_rev,
9497 .capsrc_nids = alc883_capsrc_nids_rev,
9498 .dig_out_nid = ALC883_DIGOUT_NID,
9499 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9500 .channel_mode = alc883_3ST_6ch_modes,
9501 .need_dac_fix = 1,
9502 .const_channel_count = 6,
9503 .input_mux = &alc883_capture_source,
9504 .unsol_event = alc_automute_amp_unsol_event,
9505 .setup = alc888_acer_aspire_6530g_setup,
9506 .init_hook = alc_automute_amp,
9507 },
Tobin Davisc07584c2006-10-13 12:32:16 +02009508 [ALC883_MEDION] = {
9509 .mixers = { alc883_fivestack_mixer,
9510 alc883_chmode_mixer },
9511 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01009512 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +02009513 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9514 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009515 .adc_nids = alc883_adc_nids_alt,
9516 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Tobin Davisc07584c2006-10-13 12:32:16 +02009517 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9518 .channel_mode = alc883_sixstack_modes,
9519 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01009520 },
Kailang Yang272a5272007-05-14 11:00:38 +02009521 [ALC883_MEDION_MD2] = {
9522 .mixers = { alc883_medion_md2_mixer},
9523 .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
9524 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9525 .dac_nids = alc883_dac_nids,
9526 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02009527 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9528 .channel_mode = alc883_3ST_2ch_modes,
9529 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009530 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009531 .setup = alc883_medion_md2_setup,
9532 .init_hook = alc_automute_amp,
Kailang Yangea1fb292008-08-26 12:58:38 +02009533 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01009534 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02009535 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01009536 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
9537 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9538 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01009539 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9540 .channel_mode = alc883_3ST_2ch_modes,
9541 .input_mux = &alc883_capture_source,
9542 },
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309543 [ALC883_CLEVO_M540R] = {
9544 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9545 .init_verbs = { alc883_init_verbs, alc883_clevo_m540r_verbs },
9546 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9547 .dac_nids = alc883_dac_nids,
9548 .dig_out_nid = ALC883_DIGOUT_NID,
9549 .dig_in_nid = ALC883_DIGIN_NID,
9550 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_clevo_modes),
9551 .channel_mode = alc883_3ST_6ch_clevo_modes,
9552 .need_dac_fix = 1,
9553 .input_mux = &alc883_capture_source,
9554 /* This machine has the hardware HP auto-muting, thus
9555 * we need no software mute via unsol event
9556 */
9557 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009558 [ALC883_CLEVO_M720] = {
9559 .mixers = { alc883_clevo_m720_mixer },
9560 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +01009561 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9562 .dac_nids = alc883_dac_nids,
9563 .dig_out_nid = ALC883_DIGOUT_NID,
9564 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9565 .channel_mode = alc883_3ST_2ch_modes,
9566 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009567 .unsol_event = alc883_clevo_m720_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009568 .setup = alc883_clevo_m720_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009569 .init_hook = alc883_clevo_m720_init_hook,
Jiang zhe368c7a92008-03-04 11:20:33 +01009570 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009571 [ALC883_LENOVO_101E_2ch] = {
9572 .mixers = { alc883_lenovo_101e_2ch_mixer},
9573 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
9574 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9575 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009576 .adc_nids = alc883_adc_nids_alt,
9577 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009578 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9579 .channel_mode = alc883_3ST_2ch_modes,
9580 .input_mux = &alc883_lenovo_101e_capture_source,
9581 .unsol_event = alc883_lenovo_101e_unsol_event,
9582 .init_hook = alc883_lenovo_101e_all_automute,
9583 },
Kailang Yang272a5272007-05-14 11:00:38 +02009584 [ALC883_LENOVO_NB0763] = {
9585 .mixers = { alc883_lenovo_nb0763_mixer },
9586 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
9587 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9588 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02009589 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9590 .channel_mode = alc883_3ST_2ch_modes,
9591 .need_dac_fix = 1,
9592 .input_mux = &alc883_lenovo_nb0763_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009593 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009594 .setup = alc883_medion_md2_setup,
9595 .init_hook = alc_automute_amp,
Kailang Yang272a5272007-05-14 11:00:38 +02009596 },
9597 [ALC888_LENOVO_MS7195_DIG] = {
9598 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9599 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
9600 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9601 .dac_nids = alc883_dac_nids,
9602 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02009603 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9604 .channel_mode = alc883_3ST_6ch_modes,
9605 .need_dac_fix = 1,
9606 .input_mux = &alc883_capture_source,
9607 .unsol_event = alc883_lenovo_ms7195_unsol_event,
9608 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +02009609 },
9610 [ALC883_HAIER_W66] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -04009611 .mixers = { alc883_targa_2ch_mixer},
Kailang Yang189609a2007-08-20 11:31:23 +02009612 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
9613 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9614 .dac_nids = alc883_dac_nids,
9615 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +02009616 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9617 .channel_mode = alc883_3ST_2ch_modes,
9618 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009619 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009620 .setup = alc883_haier_w66_setup,
9621 .init_hook = alc_automute_amp,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01009622 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009623 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01009624 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009625 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009626 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9627 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009628 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
9629 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009630 .need_dac_fix = 1,
9631 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009632 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009633 .setup = alc888_3st_hp_setup,
9634 .init_hook = alc_automute_amp,
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009635 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009636 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +01009637 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009638 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
9639 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9640 .dac_nids = alc883_dac_nids,
9641 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009642 .dig_in_nid = ALC883_DIGIN_NID,
9643 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9644 .channel_mode = alc883_sixstack_modes,
9645 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009646 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009647 .setup = alc888_6st_dell_setup,
9648 .init_hook = alc_automute_amp,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009649 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009650 [ALC883_MITAC] = {
9651 .mixers = { alc883_mitac_mixer },
9652 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
9653 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9654 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009655 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9656 .channel_mode = alc883_3ST_2ch_modes,
9657 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009658 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009659 .setup = alc883_mitac_setup,
9660 .init_hook = alc_automute_amp,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009661 },
Jiang zhefb97dc62008-03-06 11:07:11 +01009662 [ALC883_FUJITSU_PI2515] = {
9663 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
9664 .init_verbs = { alc883_init_verbs,
9665 alc883_2ch_fujitsu_pi2515_verbs},
9666 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9667 .dac_nids = alc883_dac_nids,
9668 .dig_out_nid = ALC883_DIGOUT_NID,
9669 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9670 .channel_mode = alc883_3ST_2ch_modes,
9671 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009672 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009673 .setup = alc883_2ch_fujitsu_pi2515_setup,
9674 .init_hook = alc_automute_amp,
Jiang zhefb97dc62008-03-06 11:07:11 +01009675 },
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009676 [ALC888_FUJITSU_XA3530] = {
9677 .mixers = { alc888_base_mixer, alc883_chmode_mixer },
9678 .init_verbs = { alc883_init_verbs,
9679 alc888_fujitsu_xa3530_verbs },
9680 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9681 .dac_nids = alc883_dac_nids,
9682 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
9683 .adc_nids = alc883_adc_nids_rev,
9684 .capsrc_nids = alc883_capsrc_nids_rev,
9685 .dig_out_nid = ALC883_DIGOUT_NID,
9686 .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes),
9687 .channel_mode = alc888_4ST_8ch_intel_modes,
9688 .num_mux_defs =
9689 ARRAY_SIZE(alc888_2_capture_sources),
9690 .input_mux = alc888_2_capture_sources,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009691 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009692 .setup = alc888_fujitsu_xa3530_setup,
9693 .init_hook = alc_automute_amp,
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009694 },
Kailang Yange2757d52008-08-26 13:17:46 +02009695 [ALC888_LENOVO_SKY] = {
9696 .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
9697 .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
9698 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9699 .dac_nids = alc883_dac_nids,
9700 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yange2757d52008-08-26 13:17:46 +02009701 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9702 .channel_mode = alc883_sixstack_modes,
9703 .need_dac_fix = 1,
9704 .input_mux = &alc883_lenovo_sky_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009705 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009706 .setup = alc888_lenovo_sky_setup,
9707 .init_hook = alc_automute_amp,
Kailang Yange2757d52008-08-26 13:17:46 +02009708 },
9709 [ALC888_ASUS_M90V] = {
9710 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9711 .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
9712 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9713 .dac_nids = alc883_dac_nids,
9714 .dig_out_nid = ALC883_DIGOUT_NID,
9715 .dig_in_nid = ALC883_DIGIN_NID,
9716 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9717 .channel_mode = alc883_3ST_6ch_modes,
9718 .need_dac_fix = 1,
9719 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009720 .unsol_event = alc_sku_unsol_event,
9721 .setup = alc883_mode2_setup,
9722 .init_hook = alc_inithook,
Kailang Yange2757d52008-08-26 13:17:46 +02009723 },
9724 [ALC888_ASUS_EEE1601] = {
9725 .mixers = { alc883_asus_eee1601_mixer },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009726 .cap_mixer = alc883_asus_eee1601_cap_mixer,
Kailang Yange2757d52008-08-26 13:17:46 +02009727 .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
9728 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9729 .dac_nids = alc883_dac_nids,
9730 .dig_out_nid = ALC883_DIGOUT_NID,
9731 .dig_in_nid = ALC883_DIGIN_NID,
9732 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9733 .channel_mode = alc883_3ST_2ch_modes,
9734 .need_dac_fix = 1,
9735 .input_mux = &alc883_asus_eee1601_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009736 .unsol_event = alc_sku_unsol_event,
Kailang Yange2757d52008-08-26 13:17:46 +02009737 .init_hook = alc883_eee1601_inithook,
9738 },
Wu Fengguang3ab90932008-11-17 09:51:09 +01009739 [ALC1200_ASUS_P5Q] = {
9740 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
9741 .init_verbs = { alc883_init_verbs },
9742 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9743 .dac_nids = alc883_dac_nids,
9744 .dig_out_nid = ALC1200_DIGOUT_NID,
9745 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangb25c9da2009-02-06 15:02:27 +08009746 .slave_dig_outs = alc1200_slave_dig_outs,
Wu Fengguang3ab90932008-11-17 09:51:09 +01009747 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9748 .channel_mode = alc883_sixstack_modes,
9749 .input_mux = &alc883_capture_source,
9750 },
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009751 [ALC889A_MB31] = {
9752 .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer},
9753 .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs,
9754 alc880_gpio1_init_verbs },
9755 .adc_nids = alc883_adc_nids,
9756 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
9757 .dac_nids = alc883_dac_nids,
9758 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9759 .channel_mode = alc889A_mb31_6ch_modes,
9760 .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes),
9761 .input_mux = &alc889A_mb31_capture_source,
9762 .dig_out_nid = ALC883_DIGOUT_NID,
9763 .unsol_event = alc889A_mb31_unsol_event,
9764 .init_hook = alc889A_mb31_automute,
9765 },
Guido Günther3e1647c2009-06-05 00:47:26 +02009766 [ALC883_SONY_VAIO_TT] = {
9767 .mixers = { alc883_vaiott_mixer },
9768 .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs },
9769 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9770 .dac_nids = alc883_dac_nids,
9771 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9772 .channel_mode = alc883_3ST_2ch_modes,
9773 .input_mux = &alc883_capture_source,
9774 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009775 .setup = alc883_vaiott_setup,
9776 .init_hook = alc_automute_amp,
Guido Günther3e1647c2009-06-05 00:47:26 +02009777 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009778};
9779
9780
9781/*
Takashi Iwai49535502009-06-30 15:28:30 +02009782 * Pin config fixes
9783 */
9784enum {
9785 PINFIX_ABIT_AW9D_MAX
9786};
9787
9788static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
9789 { 0x15, 0x01080104 }, /* side */
9790 { 0x16, 0x01011012 }, /* rear */
9791 { 0x17, 0x01016011 }, /* clfe */
9792 { }
9793};
9794
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02009795static const struct alc_fixup alc882_fixups[] = {
9796 [PINFIX_ABIT_AW9D_MAX] = {
9797 .pins = alc882_abit_aw9d_pinfix
9798 },
Takashi Iwai49535502009-06-30 15:28:30 +02009799};
9800
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02009801static struct snd_pci_quirk alc882_fixup_tbl[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02009802 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
9803 {}
9804};
9805
9806/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009807 * BIOS auto configuration
9808 */
Takashi Iwai05f5f472009-08-25 13:10:18 +02009809static int alc882_auto_create_input_ctls(struct hda_codec *codec,
9810 const struct auto_pin_cfg *cfg)
9811{
9812 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x23, 0x22);
9813}
9814
Takashi Iwai49535502009-06-30 15:28:30 +02009815static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009816 hda_nid_t nid, int pin_type,
9817 int dac_idx)
9818{
9819 /* set as output */
9820 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009821 int idx;
9822
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009823 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009824 if (spec->multiout.dac_nids[dac_idx] == 0x25)
9825 idx = 4;
9826 else
9827 idx = spec->multiout.dac_nids[dac_idx] - 2;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009828 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
9829
9830}
9831
Takashi Iwai49535502009-06-30 15:28:30 +02009832static void alc882_auto_init_multi_out(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009833{
9834 struct alc_spec *spec = codec->spec;
9835 int i;
9836
9837 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009838 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02009839 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009840 if (nid)
Takashi Iwai49535502009-06-30 15:28:30 +02009841 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009842 i);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009843 }
9844}
9845
Takashi Iwai49535502009-06-30 15:28:30 +02009846static void alc882_auto_init_hp_out(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009847{
9848 struct alc_spec *spec = codec->spec;
9849 hda_nid_t pin;
9850
Takashi Iwaieb06ed82006-09-20 17:10:27 +02009851 pin = spec->autocfg.hp_pins[0];
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009852 if (pin) /* connect to front */
9853 /* use dac 0 */
Takashi Iwai49535502009-06-30 15:28:30 +02009854 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009855 pin = spec->autocfg.speaker_pins[0];
9856 if (pin)
Takashi Iwai49535502009-06-30 15:28:30 +02009857 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009858}
9859
Takashi Iwai49535502009-06-30 15:28:30 +02009860static void alc882_auto_init_analog_input(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009861{
9862 struct alc_spec *spec = codec->spec;
9863 int i;
9864
9865 for (i = 0; i < AUTO_PIN_LAST; i++) {
9866 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai49535502009-06-30 15:28:30 +02009867 if (!nid)
9868 continue;
Takashi Iwai0d971c92009-06-30 16:11:11 +02009869 alc_set_input_pin(codec, nid, i);
Takashi Iwai49535502009-06-30 15:28:30 +02009870 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
9871 snd_hda_codec_write(codec, nid, 0,
9872 AC_VERB_SET_AMP_GAIN_MUTE,
9873 AMP_OUT_MUTE);
9874 }
9875}
9876
9877static void alc882_auto_init_input_src(struct hda_codec *codec)
9878{
9879 struct alc_spec *spec = codec->spec;
9880 int c;
9881
9882 for (c = 0; c < spec->num_adc_nids; c++) {
9883 hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
9884 hda_nid_t nid = spec->capsrc_nids[c];
9885 unsigned int mux_idx;
9886 const struct hda_input_mux *imux;
9887 int conns, mute, idx, item;
9888
9889 conns = snd_hda_get_connections(codec, nid, conn_list,
9890 ARRAY_SIZE(conn_list));
9891 if (conns < 0)
9892 continue;
9893 mux_idx = c >= spec->num_mux_defs ? 0 : c;
9894 imux = &spec->input_mux[mux_idx];
9895 for (idx = 0; idx < conns; idx++) {
9896 /* if the current connection is the selected one,
9897 * unmute it as default - otherwise mute it
9898 */
9899 mute = AMP_IN_MUTE(idx);
9900 for (item = 0; item < imux->num_items; item++) {
9901 if (imux->items[item].index == idx) {
9902 if (spec->cur_mux[c] == item)
9903 mute = AMP_IN_UNMUTE(idx);
9904 break;
9905 }
9906 }
9907 /* check if we have a selector or mixer
9908 * we could check for the widget type instead, but
9909 * just check for Amp-In presence (in case of mixer
9910 * without amp-in there is something wrong, this
9911 * function shouldn't be used or capsrc nid is wrong)
9912 */
9913 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009914 snd_hda_codec_write(codec, nid, 0,
9915 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwai49535502009-06-30 15:28:30 +02009916 mute);
9917 else if (mute != AMP_IN_MUTE(idx))
9918 snd_hda_codec_write(codec, nid, 0,
9919 AC_VERB_SET_CONNECT_SEL,
9920 idx);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009921 }
9922 }
9923}
9924
Takashi Iwai49535502009-06-30 15:28:30 +02009925/* add mic boosts if needed */
9926static int alc_auto_add_mic_boost(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009927{
9928 struct alc_spec *spec = codec->spec;
Takashi Iwai49535502009-06-30 15:28:30 +02009929 int err;
9930 hda_nid_t nid;
9931
9932 nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
9933 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
9934 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9935 "Mic Boost",
9936 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
9937 if (err < 0)
9938 return err;
9939 }
9940 nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
9941 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
9942 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9943 "Front Mic Boost",
9944 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
9945 if (err < 0)
9946 return err;
9947 }
9948 return 0;
9949}
9950
9951/* almost identical with ALC880 parser... */
9952static int alc882_parse_auto_config(struct hda_codec *codec)
9953{
9954 struct alc_spec *spec = codec->spec;
Takashi Iwai05f5f472009-08-25 13:10:18 +02009955 static hda_nid_t alc882_ignore[] = { 0x1d, 0 };
9956 int i, err;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009957
Takashi Iwai05f5f472009-08-25 13:10:18 +02009958 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
9959 alc882_ignore);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009960 if (err < 0)
9961 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +02009962 if (!spec->autocfg.line_outs)
9963 return 0; /* can't find valid BIOS pin config */
9964
9965 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
9966 if (err < 0)
9967 return err;
9968 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
9969 if (err < 0)
9970 return err;
9971 err = alc880_auto_create_extra_out(spec,
9972 spec->autocfg.speaker_pins[0],
9973 "Speaker");
9974 if (err < 0)
9975 return err;
9976 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
9977 "Headphone");
9978 if (err < 0)
9979 return err;
9980 err = alc882_auto_create_input_ctls(codec, &spec->autocfg);
9981 if (err < 0)
9982 return err;
9983
9984 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
9985
9986 /* check multiple SPDIF-out (for recent codecs) */
9987 for (i = 0; i < spec->autocfg.dig_outs; i++) {
9988 hda_nid_t dig_nid;
9989 err = snd_hda_get_connections(codec,
9990 spec->autocfg.dig_out_pins[i],
9991 &dig_nid, 1);
9992 if (err < 0)
9993 continue;
9994 if (!i)
9995 spec->multiout.dig_out_nid = dig_nid;
9996 else {
9997 spec->multiout.slave_dig_outs = spec->slave_dig_outs;
Roel Kluin71121d9f2009-11-10 20:11:55 +01009998 if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
Takashi Iwai05f5f472009-08-25 13:10:18 +02009999 break;
Roel Kluin71121d9f2009-11-10 20:11:55 +010010000 spec->slave_dig_outs[i - 1] = dig_nid;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010001 }
10002 }
10003 if (spec->autocfg.dig_in_pin)
10004 spec->dig_in_nid = ALC880_DIGIN_NID;
10005
10006 if (spec->kctls.list)
10007 add_mixer(spec, spec->kctls.list);
10008
10009 add_verb(spec, alc883_auto_init_verbs);
10010 /* if ADC 0x07 is available, initialize it, too */
10011 if (get_wcaps_type(get_wcaps(codec, 0x07)) == AC_WID_AUD_IN)
10012 add_verb(spec, alc882_adc1_init_verbs);
10013
10014 spec->num_mux_defs = 1;
10015 spec->input_mux = &spec->private_imux[0];
10016
10017 alc_ssid_check(codec, 0x15, 0x1b, 0x14);
Takashi Iwai776e1842007-08-29 15:07:11 +020010018
10019 err = alc_auto_add_mic_boost(codec);
10020 if (err < 0)
10021 return err;
10022
Takashi Iwai776e1842007-08-29 15:07:11 +020010023 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010024}
10025
10026/* additional initialization for auto-configuration model */
Takashi Iwai49535502009-06-30 15:28:30 +020010027static void alc882_auto_init(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010028{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010029 struct alc_spec *spec = codec->spec;
Takashi Iwai49535502009-06-30 15:28:30 +020010030 alc882_auto_init_multi_out(codec);
10031 alc882_auto_init_hp_out(codec);
10032 alc882_auto_init_analog_input(codec);
10033 alc882_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010034 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020010035 alc_inithook(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010036}
10037
Takashi Iwai49535502009-06-30 15:28:30 +020010038static int patch_alc882(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010039{
10040 struct alc_spec *spec;
10041 int err, board_config;
10042
10043 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
10044 if (spec == NULL)
10045 return -ENOMEM;
10046
10047 codec->spec = spec;
10048
Takashi Iwai49535502009-06-30 15:28:30 +020010049 switch (codec->vendor_id) {
10050 case 0x10ec0882:
10051 case 0x10ec0885:
10052 break;
10053 default:
10054 /* ALC883 and variants */
10055 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
10056 break;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010057 }
10058
Takashi Iwai49535502009-06-30 15:28:30 +020010059 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
10060 alc882_models,
10061 alc882_cfg_tbl);
10062
10063 if (board_config < 0 || board_config >= ALC882_MODEL_LAST)
10064 board_config = snd_hda_check_board_codec_sid_config(codec,
10065 ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
10066
10067 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020010068 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai49535502009-06-30 15:28:30 +020010069 codec->chip_name);
10070 board_config = ALC882_AUTO;
10071 }
10072
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010073 alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups);
Takashi Iwai49535502009-06-30 15:28:30 +020010074
10075 if (board_config == ALC882_AUTO) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010076 /* automatic parse from the BIOS config */
Takashi Iwai49535502009-06-30 15:28:30 +020010077 err = alc882_parse_auto_config(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010078 if (err < 0) {
10079 alc_free(codec);
10080 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010081 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010082 printk(KERN_INFO
10083 "hda_codec: Cannot set up configuration "
10084 "from BIOS. Using base mode...\n");
Takashi Iwai49535502009-06-30 15:28:30 +020010085 board_config = ALC882_3ST_DIG;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010086 }
10087 }
10088
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090010089 err = snd_hda_attach_beep_device(codec, 0x1);
10090 if (err < 0) {
10091 alc_free(codec);
10092 return err;
10093 }
10094
Takashi Iwai49535502009-06-30 15:28:30 +020010095 if (board_config != ALC882_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020010096 setup_preset(codec, &alc882_presets[board_config]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010097
Takashi Iwai49535502009-06-30 15:28:30 +020010098 spec->stream_analog_playback = &alc882_pcm_analog_playback;
10099 spec->stream_analog_capture = &alc882_pcm_analog_capture;
10100 /* FIXME: setup DAC5 */
10101 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
10102 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
10103
10104 spec->stream_digital_playback = &alc882_pcm_digital_playback;
10105 spec->stream_digital_capture = &alc882_pcm_digital_capture;
10106
10107 if (codec->vendor_id == 0x10ec0888)
Takashi Iwai4a79ba32009-04-22 16:31:35 +020010108 spec->init_amp = ALC_INIT_DEFAULT; /* always initialize */
Takashi Iwai49535502009-06-30 15:28:30 +020010109
10110 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010111 int i, j;
Takashi Iwai49535502009-06-30 15:28:30 +020010112 spec->num_adc_nids = 0;
10113 for (i = 0; i < ARRAY_SIZE(alc882_adc_nids); i++) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010114 const struct hda_input_mux *imux = spec->input_mux;
Takashi Iwai49535502009-06-30 15:28:30 +020010115 hda_nid_t cap;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010116 hda_nid_t items[16];
Takashi Iwai49535502009-06-30 15:28:30 +020010117 hda_nid_t nid = alc882_adc_nids[i];
10118 unsigned int wcap = get_wcaps(codec, nid);
10119 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020010120 wcap = get_wcaps_type(wcap);
Takashi Iwai49535502009-06-30 15:28:30 +020010121 if (wcap != AC_WID_AUD_IN)
10122 continue;
10123 spec->private_adc_nids[spec->num_adc_nids] = nid;
10124 err = snd_hda_get_connections(codec, nid, &cap, 1);
10125 if (err < 0)
10126 continue;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010127 err = snd_hda_get_connections(codec, cap, items,
10128 ARRAY_SIZE(items));
10129 if (err < 0)
10130 continue;
10131 for (j = 0; j < imux->num_items; j++)
10132 if (imux->items[j].index >= err)
10133 break;
10134 if (j < imux->num_items)
10135 continue;
Takashi Iwai49535502009-06-30 15:28:30 +020010136 spec->private_capsrc_nids[spec->num_adc_nids] = cap;
10137 spec->num_adc_nids++;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020010138 }
Takashi Iwai49535502009-06-30 15:28:30 +020010139 spec->adc_nids = spec->private_adc_nids;
10140 spec->capsrc_nids = spec->private_capsrc_nids;
Kailang Yang2f893282008-05-27 12:14:47 +020010141 }
10142
Takashi Iwaib59bdf32009-08-11 09:47:30 +020010143 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010010144 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010145
Takashi Iwai2134ea42008-01-10 16:53:55 +010010146 spec->vmaster_nid = 0x0c;
10147
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010148 codec->patch_ops = alc_patch_ops;
Takashi Iwai49535502009-06-30 15:28:30 +020010149 if (board_config == ALC882_AUTO)
10150 spec->init_hook = alc882_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020010151#ifdef CONFIG_SND_HDA_POWER_SAVE
10152 if (!spec->loopback.amplist)
Takashi Iwai49535502009-06-30 15:28:30 +020010153 spec->loopback.amplist = alc882_loopbacks;
Takashi Iwaicb53c622007-08-10 17:21:45 +020010154#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010010155 codec->proc_widget_hook = print_realtek_coef;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010156
10157 return 0;
10158}
10159
Takashi Iwai49535502009-06-30 15:28:30 +020010160
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010161/*
Kailang Yangdf694da2005-12-05 19:42:22 +010010162 * ALC262 support
10163 */
10164
10165#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
10166#define ALC262_DIGIN_NID ALC880_DIGIN_NID
10167
10168#define alc262_dac_nids alc260_dac_nids
10169#define alc262_adc_nids alc882_adc_nids
10170#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +010010171#define alc262_capsrc_nids alc882_capsrc_nids
10172#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +010010173
10174#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +010010175#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +010010176
Kailang Yang4e555fe2008-08-26 13:05:55 +020010177static hda_nid_t alc262_dmic_adc_nids[1] = {
10178 /* ADC0 */
10179 0x09
10180};
10181
10182static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
10183
Kailang Yangdf694da2005-12-05 19:42:22 +010010184static struct snd_kcontrol_new alc262_base_mixer[] = {
10185 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10186 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10187 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10188 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
10189 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10190 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10191 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10192 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010193 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010010194 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10195 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010196 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010010197 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
10198 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10199 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
10200 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010010201 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +010010202};
10203
Takashi Iwaice875f02008-01-28 18:17:43 +010010204/* update HP, line and mono-out pins according to the master switch */
10205static void alc262_hp_master_update(struct hda_codec *codec)
10206{
10207 struct alc_spec *spec = codec->spec;
10208 int val = spec->master_sw;
10209
10210 /* HP & line-out */
10211 snd_hda_codec_write_cache(codec, 0x1b, 0,
10212 AC_VERB_SET_PIN_WIDGET_CONTROL,
10213 val ? PIN_HP : 0);
10214 snd_hda_codec_write_cache(codec, 0x15, 0,
10215 AC_VERB_SET_PIN_WIDGET_CONTROL,
10216 val ? PIN_HP : 0);
10217 /* mono (speaker) depending on the HP jack sense */
10218 val = val && !spec->jack_present;
10219 snd_hda_codec_write_cache(codec, 0x16, 0,
10220 AC_VERB_SET_PIN_WIDGET_CONTROL,
10221 val ? PIN_OUT : 0);
10222}
10223
10224static void alc262_hp_bpc_automute(struct hda_codec *codec)
10225{
10226 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080010227
10228 spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
Takashi Iwaice875f02008-01-28 18:17:43 +010010229 alc262_hp_master_update(codec);
10230}
10231
10232static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
10233{
10234 if ((res >> 26) != ALC880_HP_EVENT)
10235 return;
10236 alc262_hp_bpc_automute(codec);
10237}
10238
10239static void alc262_hp_wildwest_automute(struct hda_codec *codec)
10240{
10241 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080010242
10243 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaice875f02008-01-28 18:17:43 +010010244 alc262_hp_master_update(codec);
10245}
10246
10247static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
10248 unsigned int res)
10249{
10250 if ((res >> 26) != ALC880_HP_EVENT)
10251 return;
10252 alc262_hp_wildwest_automute(codec);
10253}
10254
Takashi Iwaib72519b2009-05-08 14:31:55 +020010255#define alc262_hp_master_sw_get alc260_hp_master_sw_get
Takashi Iwaice875f02008-01-28 18:17:43 +010010256
10257static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
10258 struct snd_ctl_elem_value *ucontrol)
10259{
10260 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10261 struct alc_spec *spec = codec->spec;
10262 int val = !!*ucontrol->value.integer.value;
10263
10264 if (val == spec->master_sw)
10265 return 0;
10266 spec->master_sw = val;
10267 alc262_hp_master_update(codec);
10268 return 1;
10269}
10270
Takashi Iwaib72519b2009-05-08 14:31:55 +020010271#define ALC262_HP_MASTER_SWITCH \
10272 { \
10273 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
10274 .name = "Master Playback Switch", \
10275 .info = snd_ctl_boolean_mono_info, \
10276 .get = alc262_hp_master_sw_get, \
10277 .put = alc262_hp_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010010278 }, \
10279 { \
10280 .iface = NID_MAPPING, \
10281 .name = "Master Playback Switch", \
10282 .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \
Takashi Iwaib72519b2009-05-08 14:31:55 +020010283 }
10284
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010010285
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010286static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020010287 ALC262_HP_MASTER_SWITCH,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010288 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10289 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10290 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010010291 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
10292 HDA_OUTPUT),
10293 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
10294 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010295 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10296 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010297 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010298 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10299 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010300 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010301 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10302 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10303 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10304 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010305 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
10306 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
10307 { } /* end */
10308};
10309
Kailang Yangcd7509a2007-01-26 18:33:17 +010010310static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020010311 ALC262_HP_MASTER_SWITCH,
Kailang Yangcd7509a2007-01-26 18:33:17 +010010312 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10313 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
10314 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
10315 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010010316 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
10317 HDA_OUTPUT),
10318 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
10319 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010320 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
10321 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010322 HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010323 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
10324 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
10325 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10326 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010327 { } /* end */
10328};
10329
10330static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
10331 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10332 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010333 HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010334 { } /* end */
10335};
10336
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010337/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010338static void alc262_hp_t5735_setup(struct hda_codec *codec)
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010339{
10340 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010341
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010342 spec->autocfg.hp_pins[0] = 0x15;
10343 spec->autocfg.speaker_pins[0] = 0x0c; /* HACK: not actually a pin */
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010344}
10345
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010346static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010010347 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10348 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010349 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
10350 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10351 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10352 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10353 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10354 { } /* end */
10355};
10356
10357static struct hda_verb alc262_hp_t5735_verbs[] = {
10358 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10359 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10360
10361 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10362 { }
10363};
10364
Kailang Yang8c427222008-01-10 13:03:59 +010010365static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +010010366 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10367 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010010368 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
10369 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010010370 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
10371 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
10372 { } /* end */
10373};
10374
10375static struct hda_verb alc262_hp_rp5700_verbs[] = {
10376 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10377 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10378 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10379 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10380 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10381 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
10382 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10383 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10384 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
10385 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
10386 {}
10387};
10388
10389static struct hda_input_mux alc262_hp_rp5700_capture_source = {
10390 .num_items = 1,
10391 .items = {
10392 { "Line", 0x1 },
10393 },
10394};
10395
Takashi Iwai42171c12009-05-08 14:11:43 +020010396/* bind hp and internal speaker mute (with plug check) as master switch */
10397static void alc262_hippo_master_update(struct hda_codec *codec)
10398{
10399 struct alc_spec *spec = codec->spec;
10400 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
10401 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
10402 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
10403 unsigned int mute;
10404
10405 /* HP */
10406 mute = spec->master_sw ? 0 : HDA_AMP_MUTE;
10407 snd_hda_codec_amp_stereo(codec, hp_nid, HDA_OUTPUT, 0,
10408 HDA_AMP_MUTE, mute);
10409 /* mute internal speaker per jack sense */
10410 if (spec->jack_present)
10411 mute = HDA_AMP_MUTE;
10412 if (line_nid)
10413 snd_hda_codec_amp_stereo(codec, line_nid, HDA_OUTPUT, 0,
10414 HDA_AMP_MUTE, mute);
10415 if (speaker_nid && speaker_nid != line_nid)
10416 snd_hda_codec_amp_stereo(codec, speaker_nid, HDA_OUTPUT, 0,
10417 HDA_AMP_MUTE, mute);
10418}
10419
10420#define alc262_hippo_master_sw_get alc262_hp_master_sw_get
10421
10422static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol,
10423 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai0724ea22007-08-23 00:31:43 +020010424{
10425 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Takashi Iwai42171c12009-05-08 14:11:43 +020010426 struct alc_spec *spec = codec->spec;
10427 int val = !!*ucontrol->value.integer.value;
Takashi Iwai0724ea22007-08-23 00:31:43 +020010428
Takashi Iwai42171c12009-05-08 14:11:43 +020010429 if (val == spec->master_sw)
10430 return 0;
10431 spec->master_sw = val;
10432 alc262_hippo_master_update(codec);
10433 return 1;
Takashi Iwai0724ea22007-08-23 00:31:43 +020010434}
Takashi Iwai5b319542007-07-26 11:49:22 +020010435
Takashi Iwai42171c12009-05-08 14:11:43 +020010436#define ALC262_HIPPO_MASTER_SWITCH \
10437 { \
10438 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
10439 .name = "Master Playback Switch", \
10440 .info = snd_ctl_boolean_mono_info, \
10441 .get = alc262_hippo_master_sw_get, \
10442 .put = alc262_hippo_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010010443 }, \
10444 { \
10445 .iface = NID_MAPPING, \
10446 .name = "Master Playback Switch", \
10447 .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \
10448 (SUBDEV_SPEAKER(0) << 16), \
Takashi Iwai42171c12009-05-08 14:11:43 +020010449 }
10450
10451static struct snd_kcontrol_new alc262_hippo_mixer[] = {
10452 ALC262_HIPPO_MASTER_SWITCH,
10453 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10454 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10455 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
10456 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10457 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10458 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10459 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10460 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10461 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10462 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10463 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
10464 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
10465 { } /* end */
10466};
10467
10468static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
10469 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10470 ALC262_HIPPO_MASTER_SWITCH,
10471 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10472 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
10473 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10474 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10475 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10476 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10477 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10478 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10479 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10480 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
10481 { } /* end */
10482};
10483
10484/* mute/unmute internal speaker according to the hp jack and mute state */
10485static void alc262_hippo_automute(struct hda_codec *codec)
10486{
10487 struct alc_spec *spec = codec->spec;
10488 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
Takashi Iwai42171c12009-05-08 14:11:43 +020010489
Wu Fengguang864f92b2009-11-18 12:38:02 +080010490 spec->jack_present = snd_hda_jack_detect(codec, hp_nid);
Takashi Iwai42171c12009-05-08 14:11:43 +020010491 alc262_hippo_master_update(codec);
10492}
10493
10494static void alc262_hippo_unsol_event(struct hda_codec *codec, unsigned int res)
10495{
10496 if ((res >> 26) != ALC880_HP_EVENT)
10497 return;
10498 alc262_hippo_automute(codec);
10499}
10500
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010501static void alc262_hippo_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020010502{
10503 struct alc_spec *spec = codec->spec;
10504
10505 spec->autocfg.hp_pins[0] = 0x15;
10506 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai42171c12009-05-08 14:11:43 +020010507}
10508
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010509static void alc262_hippo1_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020010510{
10511 struct alc_spec *spec = codec->spec;
10512
10513 spec->autocfg.hp_pins[0] = 0x1b;
10514 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai42171c12009-05-08 14:11:43 +020010515}
10516
10517
Kailang Yang272a5272007-05-14 11:00:38 +020010518static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +020010519 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020010520 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang272a5272007-05-14 11:00:38 +020010521 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10522 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10523 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10524 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10525 { } /* end */
10526};
10527
Kailang Yang83c34212007-07-05 11:43:05 +020010528static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020010529 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10530 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang83c34212007-07-05 11:43:05 +020010531 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10532 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10533 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10534 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10535 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10536 { } /* end */
10537};
Kailang Yang272a5272007-05-14 11:00:38 +020010538
Tony Vroonba340e82009-02-02 19:01:30 +000010539static struct snd_kcontrol_new alc262_tyan_mixer[] = {
10540 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10541 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
10542 HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
10543 HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT),
10544 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10545 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10546 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10547 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10548 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10549 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10550 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10551 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
10552 { } /* end */
10553};
10554
10555static struct hda_verb alc262_tyan_verbs[] = {
10556 /* Headphone automute */
10557 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10558 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10559 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10560
10561 /* P11 AUX_IN, white 4-pin connector */
10562 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10563 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
10564 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
10565 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
10566
10567 {}
10568};
10569
10570/* unsolicited event for HP jack sensing */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010571static void alc262_tyan_setup(struct hda_codec *codec)
Tony Vroonba340e82009-02-02 19:01:30 +000010572{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010573 struct alc_spec *spec = codec->spec;
Tony Vroonba340e82009-02-02 19:01:30 +000010574
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010575 spec->autocfg.hp_pins[0] = 0x1b;
10576 spec->autocfg.speaker_pins[0] = 0x15;
Tony Vroonba340e82009-02-02 19:01:30 +000010577}
10578
Tony Vroonba340e82009-02-02 19:01:30 +000010579
Kailang Yangdf694da2005-12-05 19:42:22 +010010580#define alc262_capture_mixer alc882_capture_mixer
10581#define alc262_capture_alt_mixer alc882_capture_alt_mixer
10582
10583/*
10584 * generic initialization of ADC, input mixers and output mixers
10585 */
10586static struct hda_verb alc262_init_verbs[] = {
10587 /*
10588 * Unmute ADC0-2 and set the default input to mic-in
10589 */
10590 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
10591 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10592 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10593 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10594 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
10595 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10596
Takashi Iwaicb53c622007-08-10 17:21:45 +020010597 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010010598 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010599 * Note: PASD motherboards uses the Line In 2 as the input for
10600 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010010601 */
10602 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010603 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10604 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10605 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10606 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10607 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010010608
10609 /*
10610 * Set up output mixers (0x0c - 0x0e)
10611 */
10612 /* set vol=0 to output mixers */
10613 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10614 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10615 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10616 /* set up input amps for analog loopback */
10617 /* Amp Indices: DAC = 0, mixer = 1 */
10618 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10619 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10620 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10621 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10622 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10623 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10624
10625 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
10626 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
10627 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
10628 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10629 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10630 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10631
10632 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
10633 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
10634 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
10635 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
10636 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Kailang Yangea1fb292008-08-26 12:58:38 +020010637
Kailang Yangdf694da2005-12-05 19:42:22 +010010638 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
10639 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Kailang Yangea1fb292008-08-26 12:58:38 +020010640
Kailang Yangdf694da2005-12-05 19:42:22 +010010641 /* FIXME: use matrix-type input source selection */
10642 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10643 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10644 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10645 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10646 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10647 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10648 /* Input mixer2 */
10649 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10650 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10651 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10652 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10653 /* Input mixer3 */
10654 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10655 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10656 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010657 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +010010658
10659 { }
10660};
10661
Kailang Yang4e555fe2008-08-26 13:05:55 +020010662static struct hda_verb alc262_eapd_verbs[] = {
10663 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
10664 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
10665 { }
10666};
10667
Kailang Yangccc656c2006-10-17 12:32:26 +020010668static struct hda_verb alc262_hippo1_unsol_verbs[] = {
10669 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
10670 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
10671 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
10672
10673 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10674 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10675 {}
10676};
10677
Kailang Yang272a5272007-05-14 11:00:38 +020010678static struct hda_verb alc262_sony_unsol_verbs[] = {
10679 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
10680 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10681 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
10682
10683 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10684 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +090010685 {}
Kailang Yang272a5272007-05-14 11:00:38 +020010686};
10687
Kailang Yang4e555fe2008-08-26 13:05:55 +020010688static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
10689 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10690 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10691 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10692 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10693 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang4e555fe2008-08-26 13:05:55 +020010694 { } /* end */
10695};
10696
10697static struct hda_verb alc262_toshiba_s06_verbs[] = {
10698 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10699 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10700 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10701 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10702 {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
10703 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10704 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
10705 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10706 {}
10707};
10708
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010709static void alc262_toshiba_s06_setup(struct hda_codec *codec)
Kailang Yang4e555fe2008-08-26 13:05:55 +020010710{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010711 struct alc_spec *spec = codec->spec;
10712
10713 spec->autocfg.hp_pins[0] = 0x15;
10714 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010715 spec->ext_mic.pin = 0x18;
10716 spec->ext_mic.mux_idx = 0;
10717 spec->int_mic.pin = 0x12;
10718 spec->int_mic.mux_idx = 9;
10719 spec->auto_mic = 1;
Kailang Yang4e555fe2008-08-26 13:05:55 +020010720}
10721
Takashi Iwai834be882006-03-01 14:16:17 +010010722/*
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010723 * nec model
10724 * 0x15 = headphone
10725 * 0x16 = internal speaker
10726 * 0x18 = external mic
10727 */
10728
10729static struct snd_kcontrol_new alc262_nec_mixer[] = {
10730 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
10731 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
10732
10733 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10734 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10735 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10736
10737 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
10738 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10739 { } /* end */
10740};
10741
10742static struct hda_verb alc262_nec_verbs[] = {
10743 /* Unmute Speaker */
10744 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10745
10746 /* Headphone */
10747 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10748 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10749
10750 /* External mic to headphone */
10751 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10752 /* External mic to speaker */
10753 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10754 {}
10755};
10756
10757/*
Takashi Iwai834be882006-03-01 14:16:17 +010010758 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +010010759 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
10760 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +010010761 */
10762
10763#define ALC_HP_EVENT 0x37
10764
10765static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
10766 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
10767 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +010010768 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
10769 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +010010770 {}
10771};
10772
Jiang zhe0e31daf2008-03-20 12:12:39 +010010773static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
10774 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
10775 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10776 {}
10777};
10778
Takashi Iwai834be882006-03-01 14:16:17 +010010779static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +020010780 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +010010781 .items = {
10782 { "Mic", 0x0 },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020010783 { "Int Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +010010784 { "CD", 0x4 },
10785 },
10786};
10787
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010788static struct hda_input_mux alc262_HP_capture_source = {
10789 .num_items = 5,
10790 .items = {
10791 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +020010792 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010793 { "Line", 0x2 },
10794 { "CD", 0x4 },
10795 { "AUX IN", 0x6 },
10796 },
10797};
10798
zhejiangaccbe492007-08-31 12:36:05 +020010799static struct hda_input_mux alc262_HP_D7000_capture_source = {
10800 .num_items = 4,
10801 .items = {
10802 { "Mic", 0x0 },
10803 { "Front Mic", 0x2 },
10804 { "Line", 0x1 },
10805 { "CD", 0x4 },
10806 },
10807};
10808
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010809/* mute/unmute internal speaker according to the hp jacks and mute state */
Takashi Iwai834be882006-03-01 14:16:17 +010010810static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
10811{
10812 struct alc_spec *spec = codec->spec;
10813 unsigned int mute;
10814
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010815 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080010816 spec->jack_present = snd_hda_jack_detect(codec, 0x14) ||
10817 snd_hda_jack_detect(codec, 0x1b);
Takashi Iwai834be882006-03-01 14:16:17 +010010818 spec->sense_updated = 1;
10819 }
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010820 /* unmute internal speaker only if both HPs are unplugged and
10821 * master switch is on
10822 */
10823 if (spec->jack_present)
10824 mute = HDA_AMP_MUTE;
10825 else
Takashi Iwai834be882006-03-01 14:16:17 +010010826 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010827 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
10828 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +010010829}
10830
10831/* unsolicited event for HP jack sensing */
10832static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
10833 unsigned int res)
10834{
10835 if ((res >> 26) != ALC_HP_EVENT)
10836 return;
10837 alc262_fujitsu_automute(codec, 1);
10838}
10839
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010840static void alc262_fujitsu_init_hook(struct hda_codec *codec)
10841{
10842 alc262_fujitsu_automute(codec, 1);
10843}
10844
Takashi Iwai834be882006-03-01 14:16:17 +010010845/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +020010846static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
10847 .ops = &snd_hda_bind_vol,
10848 .values = {
10849 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
10850 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
10851 0
10852 },
10853};
Takashi Iwai834be882006-03-01 14:16:17 +010010854
Jiang zhe0e31daf2008-03-20 12:12:39 +010010855/* mute/unmute internal speaker according to the hp jack and mute state */
10856static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
10857{
10858 struct alc_spec *spec = codec->spec;
10859 unsigned int mute;
10860
10861 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080010862 spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
Jiang zhe0e31daf2008-03-20 12:12:39 +010010863 spec->sense_updated = 1;
10864 }
10865 if (spec->jack_present) {
10866 /* mute internal speaker */
10867 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10868 HDA_AMP_MUTE, HDA_AMP_MUTE);
10869 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
10870 HDA_AMP_MUTE, HDA_AMP_MUTE);
10871 } else {
10872 /* unmute internal speaker if necessary */
10873 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
10874 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10875 HDA_AMP_MUTE, mute);
10876 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
10877 HDA_AMP_MUTE, mute);
10878 }
10879}
10880
10881/* unsolicited event for HP jack sensing */
10882static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
10883 unsigned int res)
10884{
10885 if ((res >> 26) != ALC_HP_EVENT)
10886 return;
10887 alc262_lenovo_3000_automute(codec, 1);
10888}
10889
Takashi Iwai8de56b72009-07-24 16:51:47 +020010890static int amp_stereo_mute_update(struct hda_codec *codec, hda_nid_t nid,
10891 int dir, int idx, long *valp)
10892{
10893 int i, change = 0;
10894
10895 for (i = 0; i < 2; i++, valp++)
10896 change |= snd_hda_codec_amp_update(codec, nid, i, dir, idx,
10897 HDA_AMP_MUTE,
10898 *valp ? 0 : HDA_AMP_MUTE);
10899 return change;
10900}
10901
Takashi Iwai834be882006-03-01 14:16:17 +010010902/* bind hp and internal speaker mute (with plug check) */
10903static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
10904 struct snd_ctl_elem_value *ucontrol)
10905{
10906 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10907 long *valp = ucontrol->value.integer.value;
10908 int change;
10909
Takashi Iwai8de56b72009-07-24 16:51:47 +020010910 change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
10911 change |= amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
Takashi Iwai82beb8f2007-08-10 17:09:26 +020010912 if (change)
10913 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +010010914 return change;
10915}
10916
10917static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +020010918 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +010010919 {
10920 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10921 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010010922 .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
Takashi Iwai834be882006-03-01 14:16:17 +010010923 .info = snd_hda_mixer_amp_switch_info,
10924 .get = snd_hda_mixer_amp_switch_get,
10925 .put = alc262_fujitsu_master_sw_put,
10926 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
10927 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010010928 {
10929 .iface = NID_MAPPING,
10930 .name = "Master Playback Switch",
10931 .private_value = 0x1b,
10932 },
Takashi Iwai834be882006-03-01 14:16:17 +010010933 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10934 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
10935 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10936 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10937 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai39d3ed32007-10-12 15:03:48 +020010938 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
10939 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
10940 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010010941 { } /* end */
10942};
10943
Jiang zhe0e31daf2008-03-20 12:12:39 +010010944/* bind hp and internal speaker mute (with plug check) */
10945static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
10946 struct snd_ctl_elem_value *ucontrol)
10947{
10948 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10949 long *valp = ucontrol->value.integer.value;
10950 int change;
10951
Takashi Iwai8de56b72009-07-24 16:51:47 +020010952 change = amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
Jiang zhe0e31daf2008-03-20 12:12:39 +010010953 if (change)
10954 alc262_lenovo_3000_automute(codec, 0);
10955 return change;
10956}
10957
10958static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
10959 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
10960 {
10961 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10962 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010010963 .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
Jiang zhe0e31daf2008-03-20 12:12:39 +010010964 .info = snd_hda_mixer_amp_switch_info,
10965 .get = snd_hda_mixer_amp_switch_get,
10966 .put = alc262_lenovo_3000_master_sw_put,
10967 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
10968 },
10969 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10970 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
10971 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10972 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10973 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10974 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
10975 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
10976 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
10977 { } /* end */
10978};
10979
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010980static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
10981 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai42171c12009-05-08 14:11:43 +020010982 ALC262_HIPPO_MASTER_SWITCH,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010983 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10984 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10985 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10986 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10987 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10988 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
10989 { } /* end */
10990};
10991
Takashi Iwai304dcaa2006-07-25 14:51:16 +020010992/* additional init verbs for Benq laptops */
10993static struct hda_verb alc262_EAPD_verbs[] = {
10994 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
10995 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
10996 {}
10997};
10998
Kailang Yang83c34212007-07-05 11:43:05 +020010999static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
11000 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11001 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11002
11003 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
11004 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
11005 {}
11006};
11007
Tobin Davisf651b502007-10-26 12:40:47 +020011008/* Samsung Q1 Ultra Vista model setup */
11009static struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011010 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11011 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020011012 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11013 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11014 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011015 HDA_CODEC_VOLUME("Headphone Mic Boost", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020011016 { } /* end */
11017};
11018
11019static struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011020 /* output mixer */
11021 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11022 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11023 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11024 /* speaker */
11025 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11026 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11027 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11028 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11029 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +020011030 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011031 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11032 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11033 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11034 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11035 /* internal mic */
11036 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11037 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11038 /* ADC, choose mic */
11039 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11040 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11041 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11042 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11043 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11044 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11045 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
11046 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
11047 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
11048 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +020011049 {}
11050};
11051
Tobin Davisf651b502007-10-26 12:40:47 +020011052/* mute/unmute internal speaker according to the hp jack and mute state */
11053static void alc262_ultra_automute(struct hda_codec *codec)
11054{
11055 struct alc_spec *spec = codec->spec;
11056 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +020011057
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011058 mute = 0;
11059 /* auto-mute only when HP is used as HP */
11060 if (!spec->cur_mux[0]) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011061 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011062 if (spec->jack_present)
11063 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +020011064 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011065 /* mute/unmute internal speaker */
11066 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11067 HDA_AMP_MUTE, mute);
11068 /* mute/unmute HP */
11069 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
11070 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +020011071}
11072
11073/* unsolicited event for HP jack sensing */
11074static void alc262_ultra_unsol_event(struct hda_codec *codec,
11075 unsigned int res)
11076{
11077 if ((res >> 26) != ALC880_HP_EVENT)
11078 return;
11079 alc262_ultra_automute(codec);
11080}
11081
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011082static struct hda_input_mux alc262_ultra_capture_source = {
11083 .num_items = 2,
11084 .items = {
11085 { "Mic", 0x1 },
11086 { "Headphone", 0x7 },
11087 },
11088};
11089
11090static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
11091 struct snd_ctl_elem_value *ucontrol)
11092{
11093 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11094 struct alc_spec *spec = codec->spec;
11095 int ret;
11096
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011097 ret = alc_mux_enum_put(kcontrol, ucontrol);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011098 if (!ret)
11099 return 0;
11100 /* reprogram the HP pin as mic or HP according to the input source */
11101 snd_hda_codec_write_cache(codec, 0x15, 0,
11102 AC_VERB_SET_PIN_WIDGET_CONTROL,
11103 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
11104 alc262_ultra_automute(codec); /* mute/unmute HP */
11105 return ret;
11106}
11107
11108static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
11109 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
11110 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
11111 {
11112 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11113 .name = "Capture Source",
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011114 .info = alc_mux_enum_info,
11115 .get = alc_mux_enum_get,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011116 .put = alc262_ultra_mux_enum_put,
11117 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011118 {
11119 .iface = NID_MAPPING,
11120 .name = "Capture Source",
11121 .private_value = 0x15,
11122 },
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011123 { } /* end */
11124};
11125
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011126/* We use two mixers depending on the output pin; 0x16 is a mono output
11127 * and thus it's bound with a different mixer.
11128 * This function returns which mixer amp should be used.
11129 */
11130static int alc262_check_volbit(hda_nid_t nid)
11131{
11132 if (!nid)
11133 return 0;
11134 else if (nid == 0x16)
11135 return 2;
11136 else
11137 return 1;
11138}
11139
11140static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
11141 const char *pfx, int *vbits)
11142{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011143 unsigned long val;
11144 int vbit;
11145
11146 vbit = alc262_check_volbit(nid);
11147 if (!vbit)
11148 return 0;
11149 if (*vbits & vbit) /* a volume control for this mixer already there */
11150 return 0;
11151 *vbits |= vbit;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011152 if (vbit == 2)
11153 val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT);
11154 else
11155 val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT);
Takashi Iwai0afe5f82009-10-02 09:20:00 +020011156 return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011157}
11158
11159static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
11160 const char *pfx)
11161{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011162 unsigned long val;
11163
11164 if (!nid)
11165 return 0;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011166 if (nid == 0x16)
11167 val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
11168 else
11169 val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
Takashi Iwai0afe5f82009-10-02 09:20:00 +020011170 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011171}
11172
Kailang Yangdf694da2005-12-05 19:42:22 +010011173/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011174static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
11175 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010011176{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011177 const char *pfx;
11178 int vbits;
Kailang Yangdf694da2005-12-05 19:42:22 +010011179 int err;
11180
11181 spec->multiout.num_dacs = 1; /* only use one dac */
11182 spec->multiout.dac_nids = spec->private_dac_nids;
11183 spec->multiout.dac_nids[0] = 2;
11184
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011185 if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
11186 pfx = "Master";
11187 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
11188 pfx = "Speaker";
11189 else
11190 pfx = "Front";
11191 err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[0], pfx);
11192 if (err < 0)
11193 return err;
11194 err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[0], "Speaker");
11195 if (err < 0)
11196 return err;
11197 err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[0], "Headphone");
11198 if (err < 0)
11199 return err;
Kailang Yangdf694da2005-12-05 19:42:22 +010011200
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011201 vbits = alc262_check_volbit(cfg->line_out_pins[0]) |
11202 alc262_check_volbit(cfg->speaker_pins[0]) |
11203 alc262_check_volbit(cfg->hp_pins[0]);
11204 if (vbits == 1 || vbits == 2)
11205 pfx = "Master"; /* only one mixer is used */
11206 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
11207 pfx = "Speaker";
11208 else
11209 pfx = "Front";
11210 vbits = 0;
11211 err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[0], pfx, &vbits);
11212 if (err < 0)
11213 return err;
11214 err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[0], "Speaker",
11215 &vbits);
11216 if (err < 0)
11217 return err;
11218 err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[0], "Headphone",
11219 &vbits);
11220 if (err < 0)
11221 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011222 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +010011223}
11224
Takashi Iwai05f5f472009-08-25 13:10:18 +020011225#define alc262_auto_create_input_ctls \
11226 alc880_auto_create_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +010011227
11228/*
11229 * generic initialization of ADC, input mixers and output mixers
11230 */
11231static struct hda_verb alc262_volume_init_verbs[] = {
11232 /*
11233 * Unmute ADC0-2 and set the default input to mic-in
11234 */
11235 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11236 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11237 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11238 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11239 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11240 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11241
Takashi Iwaicb53c622007-08-10 17:21:45 +020011242 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010011243 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011244 * Note: PASD motherboards uses the Line In 2 as the input for
11245 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010011246 */
11247 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011248 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11249 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11250 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11251 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11252 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011253
11254 /*
11255 * Set up output mixers (0x0c - 0x0f)
11256 */
11257 /* set vol=0 to output mixers */
11258 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11259 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11260 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yangea1fb292008-08-26 12:58:38 +020011261
Kailang Yangdf694da2005-12-05 19:42:22 +010011262 /* set up input amps for analog loopback */
11263 /* Amp Indices: DAC = 0, mixer = 1 */
11264 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11265 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11266 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11267 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11268 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11269 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11270
11271 /* FIXME: use matrix-type input source selection */
11272 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
11273 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
11274 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11275 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11276 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11277 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11278 /* Input mixer2 */
11279 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11280 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11281 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11282 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11283 /* Input mixer3 */
11284 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11285 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11286 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11287 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11288
11289 { }
11290};
11291
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011292static struct hda_verb alc262_HP_BPC_init_verbs[] = {
11293 /*
11294 * Unmute ADC0-2 and set the default input to mic-in
11295 */
11296 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11297 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11298 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11299 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11300 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11301 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11302
Takashi Iwaicb53c622007-08-10 17:21:45 +020011303 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011304 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011305 * Note: PASD motherboards uses the Line In 2 as the input for
11306 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011307 */
11308 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011309 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11310 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11311 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11312 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11313 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11314 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
11315 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Kailang Yangea1fb292008-08-26 12:58:38 +020011316
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011317 /*
11318 * Set up output mixers (0x0c - 0x0e)
11319 */
11320 /* set vol=0 to output mixers */
11321 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11322 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11323 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11324
11325 /* set up input amps for analog loopback */
11326 /* Amp Indices: DAC = 0, mixer = 1 */
11327 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11328 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11329 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11330 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11331 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11332 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11333
Takashi Iwaice875f02008-01-28 18:17:43 +010011334 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011335 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11336 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11337
11338 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
11339 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
11340
11341 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11342 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11343
11344 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11345 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11346 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11347 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11348 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11349
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020011350 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011351 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
11352 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020011353 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011354 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
11355 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
11356
11357
11358 /* FIXME: use matrix-type input source selection */
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020011359 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */
11360 /* Input mixer1: only unmute Mic */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011361 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020011362 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
11363 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11364 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11365 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11366 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
11367 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
11368 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
11369 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011370 /* Input mixer2 */
11371 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020011372 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
11373 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11374 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11375 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11376 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
11377 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
11378 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
11379 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011380 /* Input mixer3 */
11381 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020011382 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
11383 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11384 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11385 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11386 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
11387 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
11388 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
11389 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011390
Takashi Iwaice875f02008-01-28 18:17:43 +010011391 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11392
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011393 { }
11394};
11395
Kailang Yangcd7509a2007-01-26 18:33:17 +010011396static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
11397 /*
11398 * Unmute ADC0-2 and set the default input to mic-in
11399 */
11400 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11401 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11402 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11403 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11404 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11405 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11406
Takashi Iwaicb53c622007-08-10 17:21:45 +020011407 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +010011408 * mixer widget
11409 * Note: PASD motherboards uses the Line In 2 as the input for front
11410 * panel mic (mic 2)
11411 */
11412 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011413 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11414 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11415 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11416 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11417 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11418 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
11419 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
11420 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +010011421 /*
11422 * Set up output mixers (0x0c - 0x0e)
11423 */
11424 /* set vol=0 to output mixers */
11425 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11426 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11427 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11428
11429 /* set up input amps for analog loopback */
11430 /* Amp Indices: DAC = 0, mixer = 1 */
11431 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11432 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11433 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11434 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11435 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11436 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11437
11438
11439 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
11440 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
11441 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
11442 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
11443 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
11444 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
11445 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
11446
11447 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
11448 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
11449
11450 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11451 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
11452
11453 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
11454 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
11455 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
11456 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
11457 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
11458 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
11459
11460 /* FIXME: use matrix-type input source selection */
11461 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
11462 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
11463 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
11464 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
11465 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
11466 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
11467 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
11468 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
11469 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
11470 /* Input mixer2 */
11471 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11472 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11473 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
11474 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
11475 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
11476 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
11477 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
11478 /* Input mixer3 */
11479 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11480 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11481 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
11482 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
11483 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
11484 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
11485 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
11486
Takashi Iwaice875f02008-01-28 18:17:43 +010011487 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11488
Kailang Yangcd7509a2007-01-26 18:33:17 +010011489 { }
11490};
11491
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011492static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
11493
11494 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */
11495 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
11496 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
11497
11498 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */
11499 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
11500 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
11501 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
11502
11503 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */
11504 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11505 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11506 {}
11507};
11508
11509
Takashi Iwaicb53c622007-08-10 17:21:45 +020011510#ifdef CONFIG_SND_HDA_POWER_SAVE
11511#define alc262_loopbacks alc880_loopbacks
11512#endif
11513
Sasha Alexandrdef319f2009-06-16 16:00:15 -040011514/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010011515#define alc262_pcm_analog_playback alc880_pcm_analog_playback
11516#define alc262_pcm_analog_capture alc880_pcm_analog_capture
11517#define alc262_pcm_digital_playback alc880_pcm_digital_playback
11518#define alc262_pcm_digital_capture alc880_pcm_digital_capture
11519
11520/*
11521 * BIOS auto configuration
11522 */
11523static int alc262_parse_auto_config(struct hda_codec *codec)
11524{
11525 struct alc_spec *spec = codec->spec;
11526 int err;
11527 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
11528
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011529 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
11530 alc262_ignore);
11531 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011532 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +010011533 if (!spec->autocfg.line_outs) {
Takashi Iwai0852d7a2009-02-11 11:35:15 +010011534 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
Takashi Iwaie64f14f2009-01-20 18:32:55 +010011535 spec->multiout.max_channels = 2;
11536 spec->no_analog = 1;
11537 goto dig_only;
11538 }
Kailang Yangdf694da2005-12-05 19:42:22 +010011539 return 0; /* can't find valid BIOS pin config */
Takashi Iwaie64f14f2009-01-20 18:32:55 +010011540 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011541 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
11542 if (err < 0)
11543 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020011544 err = alc262_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011545 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011546 return err;
11547
11548 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
11549
Takashi Iwaie64f14f2009-01-20 18:32:55 +010011550 dig_only:
Takashi Iwai0852d7a2009-02-11 11:35:15 +010011551 if (spec->autocfg.dig_outs) {
Kailang Yangdf694da2005-12-05 19:42:22 +010011552 spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
Takashi Iwai0852d7a2009-02-11 11:35:15 +010011553 spec->dig_out_type = spec->autocfg.dig_out_type[0];
Takashi Iwaie64f14f2009-01-20 18:32:55 +010011554 }
Kailang Yangdf694da2005-12-05 19:42:22 +010011555 if (spec->autocfg.dig_in_pin)
11556 spec->dig_in_nid = ALC262_DIGIN_NID;
11557
Takashi Iwai603c4012008-07-30 15:01:44 +020011558 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010011559 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010011560
Takashi Iwaid88897e2008-10-31 15:01:37 +010011561 add_verb(spec, alc262_volume_init_verbs);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020011562 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020011563 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010011564
Takashi Iwai776e1842007-08-29 15:07:11 +020011565 err = alc_auto_add_mic_boost(codec);
11566 if (err < 0)
11567 return err;
11568
Takashi Iwai4a79ba32009-04-22 16:31:35 +020011569 alc_ssid_check(codec, 0x15, 0x14, 0x1b);
11570
Kailang Yangdf694da2005-12-05 19:42:22 +010011571 return 1;
11572}
11573
11574#define alc262_auto_init_multi_out alc882_auto_init_multi_out
11575#define alc262_auto_init_hp_out alc882_auto_init_hp_out
11576#define alc262_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaif511b012008-08-15 16:46:42 +020011577#define alc262_auto_init_input_src alc882_auto_init_input_src
Kailang Yangdf694da2005-12-05 19:42:22 +010011578
11579
11580/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +010011581static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010011582{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011583 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010011584 alc262_auto_init_multi_out(codec);
11585 alc262_auto_init_hp_out(codec);
11586 alc262_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020011587 alc262_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011588 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020011589 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010011590}
11591
11592/*
11593 * configuration and preset
11594 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011595static const char *alc262_models[ALC262_MODEL_LAST] = {
11596 [ALC262_BASIC] = "basic",
11597 [ALC262_HIPPO] = "hippo",
11598 [ALC262_HIPPO_1] = "hippo_1",
11599 [ALC262_FUJITSU] = "fujitsu",
11600 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +010011601 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +010011602 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +010011603 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011604 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +020011605 [ALC262_BENQ_T31] = "benq-t31",
11606 [ALC262_SONY_ASSAMD] = "sony-assamd",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020011607 [ALC262_TOSHIBA_S06] = "toshiba-s06",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011608 [ALC262_TOSHIBA_RX1] = "toshiba-rx1",
Tobin Davisf651b502007-10-26 12:40:47 +020011609 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +010011610 [ALC262_LENOVO_3000] = "lenovo-3000",
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011611 [ALC262_NEC] = "nec",
Tony Vroonba340e82009-02-02 19:01:30 +000011612 [ALC262_TYAN] = "tyan",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011613 [ALC262_AUTO] = "auto",
11614};
11615
11616static struct snd_pci_quirk alc262_cfg_tbl[] = {
11617 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011618 SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
Takashi Iwaidea0a502009-02-09 17:14:52 +010011619 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
11620 ALC262_HP_BPC),
11621 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series",
11622 ALC262_HP_BPC),
Takashi Iwai53eff7e2009-02-27 17:49:44 +010011623 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
11624 ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011625 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011626 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011627 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011628 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011629 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011630 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011631 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011632 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011633 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
11634 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
11635 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011636 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
11637 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +010011638 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011639 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011640 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011641 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaibd6afe32009-03-04 11:30:25 +010011642 SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */
Takashi Iwai376b5082009-06-22 11:03:13 +020011643 SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06),
Daniel T Chen95491d92009-11-08 19:03:55 -050011644 SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO),
Takashi Iwai12929ba2009-11-17 15:58:35 +010011645 SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO),
Takashi Iwaic5b51652009-11-17 16:01:58 +010011646#if 0 /* disable the quirk since model=auto works better in recent versions */
Takashi Iwaif872a912009-02-26 00:57:01 +010011647 SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
11648 ALC262_SONY_ASSAMD),
Takashi Iwaic5b51652009-11-17 16:01:58 +010011649#endif
Akio Idehara36ca6e12008-06-09 22:57:40 +090011650 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011651 ALC262_TOSHIBA_RX1),
Kailang Yang80ffe862008-10-15 11:23:27 +020011652 SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011653 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +010011654 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Tony Vroonba340e82009-02-02 19:01:30 +000011655 SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
Takashi Iwaidea0a502009-02-09 17:14:52 +010011656 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1",
11657 ALC262_ULTRA),
Luke Yelavich3e420e72008-12-16 12:37:47 +110011658 SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
Jiang zhe0e31daf2008-03-20 12:12:39 +010011659 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011660 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +020011661 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011662 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +010011663 {}
11664};
11665
11666static struct alc_config_preset alc262_presets[] = {
11667 [ALC262_BASIC] = {
11668 .mixers = { alc262_base_mixer },
11669 .init_verbs = { alc262_init_verbs },
11670 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11671 .dac_nids = alc262_dac_nids,
11672 .hp_nid = 0x03,
11673 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11674 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +010011675 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +010011676 },
Kailang Yangccc656c2006-10-17 12:32:26 +020011677 [ALC262_HIPPO] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011678 .mixers = { alc262_hippo_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020011679 .init_verbs = { alc262_init_verbs, alc_hp15_unsol_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020011680 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11681 .dac_nids = alc262_dac_nids,
11682 .hp_nid = 0x03,
11683 .dig_out_nid = ALC262_DIGOUT_NID,
11684 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11685 .channel_mode = alc262_modes,
11686 .input_mux = &alc262_capture_source,
11687 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011688 .setup = alc262_hippo_setup,
11689 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020011690 },
11691 [ALC262_HIPPO_1] = {
11692 .mixers = { alc262_hippo1_mixer },
11693 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
11694 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11695 .dac_nids = alc262_dac_nids,
11696 .hp_nid = 0x02,
11697 .dig_out_nid = ALC262_DIGOUT_NID,
11698 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11699 .channel_mode = alc262_modes,
11700 .input_mux = &alc262_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020011701 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011702 .setup = alc262_hippo1_setup,
11703 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020011704 },
Takashi Iwai834be882006-03-01 14:16:17 +010011705 [ALC262_FUJITSU] = {
11706 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011707 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
11708 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +010011709 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11710 .dac_nids = alc262_dac_nids,
11711 .hp_nid = 0x03,
11712 .dig_out_nid = ALC262_DIGOUT_NID,
11713 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11714 .channel_mode = alc262_modes,
11715 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010011716 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011717 .init_hook = alc262_fujitsu_init_hook,
Takashi Iwai834be882006-03-01 14:16:17 +010011718 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011719 [ALC262_HP_BPC] = {
11720 .mixers = { alc262_HP_BPC_mixer },
11721 .init_verbs = { alc262_HP_BPC_init_verbs },
11722 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11723 .dac_nids = alc262_dac_nids,
11724 .hp_nid = 0x03,
11725 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11726 .channel_mode = alc262_modes,
11727 .input_mux = &alc262_HP_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010011728 .unsol_event = alc262_hp_bpc_unsol_event,
11729 .init_hook = alc262_hp_bpc_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011730 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010011731 [ALC262_HP_BPC_D7000_WF] = {
11732 .mixers = { alc262_HP_BPC_WildWest_mixer },
11733 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
11734 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11735 .dac_nids = alc262_dac_nids,
11736 .hp_nid = 0x03,
11737 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11738 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020011739 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010011740 .unsol_event = alc262_hp_wildwest_unsol_event,
11741 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011742 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010011743 [ALC262_HP_BPC_D7000_WL] = {
11744 .mixers = { alc262_HP_BPC_WildWest_mixer,
11745 alc262_HP_BPC_WildWest_option_mixer },
11746 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
11747 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11748 .dac_nids = alc262_dac_nids,
11749 .hp_nid = 0x03,
11750 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11751 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020011752 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010011753 .unsol_event = alc262_hp_wildwest_unsol_event,
11754 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011755 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011756 [ALC262_HP_TC_T5735] = {
11757 .mixers = { alc262_hp_t5735_mixer },
11758 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
11759 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11760 .dac_nids = alc262_dac_nids,
11761 .hp_nid = 0x03,
11762 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11763 .channel_mode = alc262_modes,
11764 .input_mux = &alc262_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011765 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011766 .setup = alc262_hp_t5735_setup,
11767 .init_hook = alc_automute_amp,
Kailang Yang8c427222008-01-10 13:03:59 +010011768 },
11769 [ALC262_HP_RP5700] = {
11770 .mixers = { alc262_hp_rp5700_mixer },
11771 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
11772 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11773 .dac_nids = alc262_dac_nids,
11774 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11775 .channel_mode = alc262_modes,
11776 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011777 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +020011778 [ALC262_BENQ_ED8] = {
11779 .mixers = { alc262_base_mixer },
11780 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
11781 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11782 .dac_nids = alc262_dac_nids,
11783 .hp_nid = 0x03,
11784 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11785 .channel_mode = alc262_modes,
11786 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011787 },
Kailang Yang272a5272007-05-14 11:00:38 +020011788 [ALC262_SONY_ASSAMD] = {
11789 .mixers = { alc262_sony_mixer },
11790 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
11791 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11792 .dac_nids = alc262_dac_nids,
11793 .hp_nid = 0x02,
11794 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11795 .channel_mode = alc262_modes,
11796 .input_mux = &alc262_capture_source,
11797 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011798 .setup = alc262_hippo_setup,
11799 .init_hook = alc262_hippo_automute,
Kailang Yang83c34212007-07-05 11:43:05 +020011800 },
11801 [ALC262_BENQ_T31] = {
11802 .mixers = { alc262_benq_t31_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020011803 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs,
11804 alc_hp15_unsol_verbs },
Kailang Yang83c34212007-07-05 11:43:05 +020011805 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11806 .dac_nids = alc262_dac_nids,
11807 .hp_nid = 0x03,
11808 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11809 .channel_mode = alc262_modes,
11810 .input_mux = &alc262_capture_source,
11811 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011812 .setup = alc262_hippo_setup,
11813 .init_hook = alc262_hippo_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020011814 },
Tobin Davisf651b502007-10-26 12:40:47 +020011815 [ALC262_ULTRA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010011816 .mixers = { alc262_ultra_mixer },
11817 .cap_mixer = alc262_ultra_capture_mixer,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011818 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +020011819 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11820 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +020011821 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11822 .channel_mode = alc262_modes,
11823 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011824 .adc_nids = alc262_adc_nids, /* ADC0 */
11825 .capsrc_nids = alc262_capsrc_nids,
11826 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +020011827 .unsol_event = alc262_ultra_unsol_event,
11828 .init_hook = alc262_ultra_automute,
11829 },
Jiang zhe0e31daf2008-03-20 12:12:39 +010011830 [ALC262_LENOVO_3000] = {
11831 .mixers = { alc262_lenovo_3000_mixer },
11832 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
11833 alc262_lenovo_3000_unsol_verbs },
11834 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11835 .dac_nids = alc262_dac_nids,
11836 .hp_nid = 0x03,
11837 .dig_out_nid = ALC262_DIGOUT_NID,
11838 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11839 .channel_mode = alc262_modes,
11840 .input_mux = &alc262_fujitsu_capture_source,
11841 .unsol_event = alc262_lenovo_3000_unsol_event,
11842 },
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011843 [ALC262_NEC] = {
11844 .mixers = { alc262_nec_mixer },
11845 .init_verbs = { alc262_nec_verbs },
11846 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11847 .dac_nids = alc262_dac_nids,
11848 .hp_nid = 0x03,
11849 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11850 .channel_mode = alc262_modes,
11851 .input_mux = &alc262_capture_source,
11852 },
Kailang Yang4e555fe2008-08-26 13:05:55 +020011853 [ALC262_TOSHIBA_S06] = {
11854 .mixers = { alc262_toshiba_s06_mixer },
11855 .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
11856 alc262_eapd_verbs },
11857 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11858 .capsrc_nids = alc262_dmic_capsrc_nids,
11859 .dac_nids = alc262_dac_nids,
11860 .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
Takashi Iwaiae14ef62009-06-22 08:16:56 +020011861 .num_adc_nids = 1, /* single ADC */
Kailang Yang4e555fe2008-08-26 13:05:55 +020011862 .dig_out_nid = ALC262_DIGOUT_NID,
11863 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11864 .channel_mode = alc262_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011865 .unsol_event = alc_sku_unsol_event,
11866 .setup = alc262_toshiba_s06_setup,
11867 .init_hook = alc_inithook,
Kailang Yang4e555fe2008-08-26 13:05:55 +020011868 },
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011869 [ALC262_TOSHIBA_RX1] = {
11870 .mixers = { alc262_toshiba_rx1_mixer },
11871 .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
11872 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11873 .dac_nids = alc262_dac_nids,
11874 .hp_nid = 0x03,
11875 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11876 .channel_mode = alc262_modes,
11877 .input_mux = &alc262_capture_source,
11878 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011879 .setup = alc262_hippo_setup,
11880 .init_hook = alc262_hippo_automute,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011881 },
Tony Vroonba340e82009-02-02 19:01:30 +000011882 [ALC262_TYAN] = {
11883 .mixers = { alc262_tyan_mixer },
11884 .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
11885 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11886 .dac_nids = alc262_dac_nids,
11887 .hp_nid = 0x02,
11888 .dig_out_nid = ALC262_DIGOUT_NID,
11889 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11890 .channel_mode = alc262_modes,
11891 .input_mux = &alc262_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011892 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011893 .setup = alc262_tyan_setup,
11894 .init_hook = alc_automute_amp,
Tony Vroonba340e82009-02-02 19:01:30 +000011895 },
Kailang Yangdf694da2005-12-05 19:42:22 +010011896};
11897
11898static int patch_alc262(struct hda_codec *codec)
11899{
11900 struct alc_spec *spec;
11901 int board_config;
11902 int err;
11903
Robert P. J. Daydc041e02006-12-19 14:44:15 +010011904 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010011905 if (spec == NULL)
11906 return -ENOMEM;
11907
11908 codec->spec = spec;
11909#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011910 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
11911 * under-run
11912 */
Kailang Yangdf694da2005-12-05 19:42:22 +010011913 {
11914 int tmp;
11915 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
11916 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
11917 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
11918 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
11919 }
11920#endif
11921
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020011922 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
11923
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011924 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
11925 alc262_models,
11926 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +010011927
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011928 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020011929 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
11930 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010011931 board_config = ALC262_AUTO;
11932 }
11933
11934 if (board_config == ALC262_AUTO) {
11935 /* automatic parse from the BIOS config */
11936 err = alc262_parse_auto_config(codec);
11937 if (err < 0) {
11938 alc_free(codec);
11939 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011940 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011941 printk(KERN_INFO
11942 "hda_codec: Cannot set up configuration "
11943 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010011944 board_config = ALC262_BASIC;
11945 }
11946 }
11947
Takashi Iwai07eba612009-02-19 08:06:35 +010011948 if (!spec->no_analog) {
11949 err = snd_hda_attach_beep_device(codec, 0x1);
11950 if (err < 0) {
11951 alc_free(codec);
11952 return err;
11953 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090011954 }
11955
Kailang Yangdf694da2005-12-05 19:42:22 +010011956 if (board_config != ALC262_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020011957 setup_preset(codec, &alc262_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010011958
Kailang Yangdf694da2005-12-05 19:42:22 +010011959 spec->stream_analog_playback = &alc262_pcm_analog_playback;
11960 spec->stream_analog_capture = &alc262_pcm_analog_capture;
Kailang Yangea1fb292008-08-26 12:58:38 +020011961
Kailang Yangdf694da2005-12-05 19:42:22 +010011962 spec->stream_digital_playback = &alc262_pcm_digital_playback;
11963 spec->stream_digital_capture = &alc262_pcm_digital_capture;
11964
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011965 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwai8c927b42009-06-22 10:56:54 +020011966 int i;
11967 /* check whether the digital-mic has to be supported */
11968 for (i = 0; i < spec->input_mux->num_items; i++) {
11969 if (spec->input_mux->items[i].index >= 9)
11970 break;
11971 }
11972 if (i < spec->input_mux->num_items) {
11973 /* use only ADC0 */
11974 spec->adc_nids = alc262_dmic_adc_nids;
11975 spec->num_adc_nids = 1;
11976 spec->capsrc_nids = alc262_dmic_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +010011977 } else {
Takashi Iwai8c927b42009-06-22 10:56:54 +020011978 /* all analog inputs */
11979 /* check whether NID 0x07 is valid */
11980 unsigned int wcap = get_wcaps(codec, 0x07);
11981
11982 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020011983 wcap = get_wcaps_type(wcap);
Takashi Iwai8c927b42009-06-22 10:56:54 +020011984 if (wcap != AC_WID_AUD_IN) {
11985 spec->adc_nids = alc262_adc_nids_alt;
11986 spec->num_adc_nids =
11987 ARRAY_SIZE(alc262_adc_nids_alt);
11988 spec->capsrc_nids = alc262_capsrc_nids_alt;
11989 } else {
11990 spec->adc_nids = alc262_adc_nids;
11991 spec->num_adc_nids =
11992 ARRAY_SIZE(alc262_adc_nids);
11993 spec->capsrc_nids = alc262_capsrc_nids;
11994 }
Kailang Yangdf694da2005-12-05 19:42:22 +010011995 }
11996 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +010011997 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020011998 set_capture_mixer(codec);
Takashi Iwai07eba612009-02-19 08:06:35 +010011999 if (!spec->no_analog)
12000 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Kailang Yangdf694da2005-12-05 19:42:22 +010012001
Takashi Iwai2134ea42008-01-10 16:53:55 +010012002 spec->vmaster_nid = 0x0c;
12003
Kailang Yangdf694da2005-12-05 19:42:22 +010012004 codec->patch_ops = alc_patch_ops;
12005 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012006 spec->init_hook = alc262_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020012007#ifdef CONFIG_SND_HDA_POWER_SAVE
12008 if (!spec->loopback.amplist)
12009 spec->loopback.amplist = alc262_loopbacks;
12010#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010012011 codec->proc_widget_hook = print_realtek_coef;
Kailang Yangea1fb292008-08-26 12:58:38 +020012012
Kailang Yangdf694da2005-12-05 19:42:22 +010012013 return 0;
12014}
12015
Kailang Yangdf694da2005-12-05 19:42:22 +010012016/*
Kailang Yanga361d842007-06-05 12:30:55 +020012017 * ALC268 channel source setting (2 channel)
12018 */
12019#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
12020#define alc268_modes alc260_modes
Kailang Yangea1fb292008-08-26 12:58:38 +020012021
Kailang Yanga361d842007-06-05 12:30:55 +020012022static hda_nid_t alc268_dac_nids[2] = {
12023 /* front, hp */
12024 0x02, 0x03
12025};
12026
12027static hda_nid_t alc268_adc_nids[2] = {
12028 /* ADC0-1 */
12029 0x08, 0x07
12030};
12031
12032static hda_nid_t alc268_adc_nids_alt[1] = {
12033 /* ADC0 */
12034 0x08
12035};
12036
Takashi Iwaie1406342008-02-11 18:32:32 +010012037static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
12038
Kailang Yanga361d842007-06-05 12:30:55 +020012039static struct snd_kcontrol_new alc268_base_mixer[] = {
12040 /* output mixer control */
12041 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12042 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12043 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12044 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai33bf17a2007-08-21 11:51:42 +020012045 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12046 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12047 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +020012048 { }
12049};
12050
Takashi Iwai42171c12009-05-08 14:11:43 +020012051static struct snd_kcontrol_new alc268_toshiba_mixer[] = {
12052 /* output mixer control */
12053 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12054 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12055 ALC262_HIPPO_MASTER_SWITCH,
12056 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12057 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12058 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
12059 { }
12060};
12061
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012062/* bind Beep switches of both NID 0x0f and 0x10 */
12063static struct hda_bind_ctls alc268_bind_beep_sw = {
12064 .ops = &snd_hda_bind_sw,
12065 .values = {
12066 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
12067 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
12068 0
12069 },
12070};
12071
12072static struct snd_kcontrol_new alc268_beep_mixer[] = {
12073 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
12074 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
12075 { }
12076};
12077
Kailang Yangd1a991a2007-08-15 16:21:59 +020012078static struct hda_verb alc268_eapd_verbs[] = {
12079 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
12080 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
12081 { }
12082};
12083
Takashi Iwaid2738092007-08-16 14:59:45 +020012084/* Toshiba specific */
Takashi Iwaid2738092007-08-16 14:59:45 +020012085static struct hda_verb alc268_toshiba_verbs[] = {
12086 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12087 { } /* end */
12088};
12089
12090/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +020012091/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +020012092static struct hda_bind_ctls alc268_acer_bind_master_vol = {
12093 .ops = &snd_hda_bind_vol,
12094 .values = {
12095 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
12096 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
12097 0
12098 },
12099};
12100
Takashi Iwai889c4392007-08-23 18:56:52 +020012101/* mute/unmute internal speaker according to the hp jack and mute state */
12102static void alc268_acer_automute(struct hda_codec *codec, int force)
12103{
12104 struct alc_spec *spec = codec->spec;
12105 unsigned int mute;
12106
12107 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080012108 spec->jack_present = snd_hda_jack_detect(codec, 0x14);
Takashi Iwai889c4392007-08-23 18:56:52 +020012109 spec->sense_updated = 1;
12110 }
12111 if (spec->jack_present)
12112 mute = HDA_AMP_MUTE; /* mute internal speaker */
12113 else /* unmute internal speaker if necessary */
12114 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
12115 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
12116 HDA_AMP_MUTE, mute);
12117}
12118
12119
12120/* bind hp and internal speaker mute (with plug check) */
12121static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
12122 struct snd_ctl_elem_value *ucontrol)
12123{
12124 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
12125 long *valp = ucontrol->value.integer.value;
12126 int change;
12127
Takashi Iwai8de56b72009-07-24 16:51:47 +020012128 change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
Takashi Iwai889c4392007-08-23 18:56:52 +020012129 if (change)
12130 alc268_acer_automute(codec, 0);
12131 return change;
12132}
Takashi Iwaid2738092007-08-16 14:59:45 +020012133
Kailang Yang8ef355d2008-08-26 13:10:22 +020012134static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
12135 /* output mixer control */
12136 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12137 {
12138 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12139 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010012140 .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
Kailang Yang8ef355d2008-08-26 13:10:22 +020012141 .info = snd_hda_mixer_amp_switch_info,
12142 .get = snd_hda_mixer_amp_switch_get,
12143 .put = alc268_acer_master_sw_put,
12144 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12145 },
12146 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
12147 { }
12148};
12149
Takashi Iwaid2738092007-08-16 14:59:45 +020012150static struct snd_kcontrol_new alc268_acer_mixer[] = {
12151 /* output mixer control */
12152 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12153 {
12154 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12155 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010012156 .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
Takashi Iwaid2738092007-08-16 14:59:45 +020012157 .info = snd_hda_mixer_amp_switch_info,
12158 .get = snd_hda_mixer_amp_switch_get,
12159 .put = alc268_acer_master_sw_put,
12160 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12161 },
Takashi Iwai33bf17a2007-08-21 11:51:42 +020012162 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12163 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
12164 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +020012165 { }
12166};
12167
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012168static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
12169 /* output mixer control */
12170 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12171 {
12172 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12173 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010012174 .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012175 .info = snd_hda_mixer_amp_switch_info,
12176 .get = snd_hda_mixer_amp_switch_get,
12177 .put = alc268_acer_master_sw_put,
12178 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12179 },
12180 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12181 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
12182 { }
12183};
12184
Kailang Yang8ef355d2008-08-26 13:10:22 +020012185static struct hda_verb alc268_acer_aspire_one_verbs[] = {
12186 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12187 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12188 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12189 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12190 {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
12191 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
12192 { }
12193};
12194
Takashi Iwaid2738092007-08-16 14:59:45 +020012195static struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012196 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
12197 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +020012198 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12199 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012200 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12201 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +020012202 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12203 { }
12204};
12205
12206/* unsolicited event for HP jack sensing */
Takashi Iwai42171c12009-05-08 14:11:43 +020012207#define alc268_toshiba_unsol_event alc262_hippo_unsol_event
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012208#define alc268_toshiba_setup alc262_hippo_setup
12209#define alc268_toshiba_automute alc262_hippo_automute
Takashi Iwaid2738092007-08-16 14:59:45 +020012210
12211static void alc268_acer_unsol_event(struct hda_codec *codec,
12212 unsigned int res)
12213{
Takashi Iwai889c4392007-08-23 18:56:52 +020012214 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020012215 return;
12216 alc268_acer_automute(codec, 1);
12217}
12218
Takashi Iwai889c4392007-08-23 18:56:52 +020012219static void alc268_acer_init_hook(struct hda_codec *codec)
12220{
12221 alc268_acer_automute(codec, 1);
12222}
12223
Kailang Yang8ef355d2008-08-26 13:10:22 +020012224/* toggle speaker-output according to the hp-jack state */
12225static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
12226{
12227 unsigned int present;
12228 unsigned char bits;
12229
Wu Fengguang864f92b2009-11-18 12:38:02 +080012230 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yang8ef355d2008-08-26 13:10:22 +020012231 bits = present ? AMP_IN_MUTE(0) : 0;
12232 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
12233 AMP_IN_MUTE(0), bits);
12234 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1,
12235 AMP_IN_MUTE(0), bits);
12236}
12237
Kailang Yang8ef355d2008-08-26 13:10:22 +020012238static void alc268_acer_lc_unsol_event(struct hda_codec *codec,
12239 unsigned int res)
12240{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012241 switch (res >> 26) {
12242 case ALC880_HP_EVENT:
Kailang Yang8ef355d2008-08-26 13:10:22 +020012243 alc268_aspire_one_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012244 break;
12245 case ALC880_MIC_EVENT:
12246 alc_mic_automute(codec);
12247 break;
12248 }
12249}
12250
12251static void alc268_acer_lc_setup(struct hda_codec *codec)
12252{
12253 struct alc_spec *spec = codec->spec;
12254 spec->ext_mic.pin = 0x18;
12255 spec->ext_mic.mux_idx = 0;
12256 spec->int_mic.pin = 0x12;
12257 spec->int_mic.mux_idx = 6;
12258 spec->auto_mic = 1;
Kailang Yang8ef355d2008-08-26 13:10:22 +020012259}
12260
12261static void alc268_acer_lc_init_hook(struct hda_codec *codec)
12262{
12263 alc268_aspire_one_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012264 alc_mic_automute(codec);
Kailang Yang8ef355d2008-08-26 13:10:22 +020012265}
12266
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012267static struct snd_kcontrol_new alc268_dell_mixer[] = {
12268 /* output mixer control */
12269 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12270 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12271 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12272 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12273 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12274 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
12275 { }
12276};
12277
12278static struct hda_verb alc268_dell_verbs[] = {
12279 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12280 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12281 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012282 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012283 { }
12284};
12285
12286/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012287static void alc268_dell_setup(struct hda_codec *codec)
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012288{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012289 struct alc_spec *spec = codec->spec;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012290
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012291 spec->autocfg.hp_pins[0] = 0x15;
12292 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012293 spec->ext_mic.pin = 0x18;
12294 spec->ext_mic.mux_idx = 0;
12295 spec->int_mic.pin = 0x19;
12296 spec->int_mic.mux_idx = 1;
12297 spec->auto_mic = 1;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012298}
12299
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012300static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
12301 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12302 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12303 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12304 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12305 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
12306 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
12307 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
12308 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
12309 { }
12310};
12311
12312static struct hda_verb alc267_quanta_il1_verbs[] = {
12313 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12314 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
12315 { }
12316};
12317
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012318static void alc267_quanta_il1_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012319{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012320 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012321 spec->autocfg.hp_pins[0] = 0x15;
12322 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012323 spec->ext_mic.pin = 0x18;
12324 spec->ext_mic.mux_idx = 0;
12325 spec->int_mic.pin = 0x19;
12326 spec->int_mic.mux_idx = 1;
12327 spec->auto_mic = 1;
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012328}
12329
Kailang Yanga361d842007-06-05 12:30:55 +020012330/*
12331 * generic initialization of ADC, input mixers and output mixers
12332 */
12333static struct hda_verb alc268_base_init_verbs[] = {
12334 /* Unmute DAC0-1 and set vol = 0 */
12335 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020012336 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020012337
12338 /*
12339 * Set up output mixers (0x0c - 0x0e)
12340 */
12341 /* set vol=0 to output mixers */
12342 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020012343 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
12344
12345 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12346 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12347
12348 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
12349 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
12350 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
12351 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12352 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12353 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12354 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12355 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12356
12357 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12358 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12359 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12360 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020012361 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012362
12363 /* set PCBEEP vol = 0, mute connections */
12364 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12365 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12366 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020012367
Jiang Zhea9b3aa82007-12-20 13:13:13 +010012368 /* Unmute Selector 23h,24h and set the default input to mic-in */
Kailang Yangea1fb292008-08-26 12:58:38 +020012369
Jiang Zhea9b3aa82007-12-20 13:13:13 +010012370 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
12371 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12372 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
12373 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020012374
Kailang Yanga361d842007-06-05 12:30:55 +020012375 { }
12376};
12377
12378/*
12379 * generic initialization of ADC, input mixers and output mixers
12380 */
12381static struct hda_verb alc268_volume_init_verbs[] = {
12382 /* set output DAC */
Takashi Iwai4cfb91c2009-01-23 12:53:09 +010012383 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12384 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020012385
12386 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12387 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12388 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12389 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12390 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12391
Kailang Yanga361d842007-06-05 12:30:55 +020012392 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020012393 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12394 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12395
12396 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020012397 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020012398
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012399 /* set PCBEEP vol = 0, mute connections */
12400 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12401 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12402 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020012403
12404 { }
12405};
12406
Takashi Iwaifdbc6622009-08-19 00:18:10 +020012407static struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = {
12408 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
12409 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
12410 { } /* end */
12411};
12412
Kailang Yanga361d842007-06-05 12:30:55 +020012413static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
12414 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
12415 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc6622009-08-19 00:18:10 +020012416 _DEFINE_CAPSRC(1),
Kailang Yanga361d842007-06-05 12:30:55 +020012417 { } /* end */
12418};
12419
12420static struct snd_kcontrol_new alc268_capture_mixer[] = {
12421 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
12422 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
12423 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
12424 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc6622009-08-19 00:18:10 +020012425 _DEFINE_CAPSRC(2),
Kailang Yanga361d842007-06-05 12:30:55 +020012426 { } /* end */
12427};
12428
12429static struct hda_input_mux alc268_capture_source = {
12430 .num_items = 4,
12431 .items = {
12432 { "Mic", 0x0 },
12433 { "Front Mic", 0x1 },
12434 { "Line", 0x2 },
12435 { "CD", 0x3 },
12436 },
12437};
12438
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012439static struct hda_input_mux alc268_acer_capture_source = {
12440 .num_items = 3,
12441 .items = {
12442 { "Mic", 0x0 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012443 { "Internal Mic", 0x1 },
12444 { "Line", 0x2 },
12445 },
12446};
12447
12448static struct hda_input_mux alc268_acer_dmic_capture_source = {
12449 .num_items = 3,
12450 .items = {
12451 { "Mic", 0x0 },
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012452 { "Internal Mic", 0x6 },
12453 { "Line", 0x2 },
12454 },
12455};
12456
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010012457#ifdef CONFIG_SND_DEBUG
12458static struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010012459 /* Volume widgets */
12460 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12461 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12462 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
12463 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
12464 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
12465 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
12466 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
12467 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
12468 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
12469 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
12470 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
12471 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
12472 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010012473 /* The below appears problematic on some hardwares */
12474 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010012475 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
12476 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
12477 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
12478 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
12479
12480 /* Modes for retasking pin widgets */
12481 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
12482 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
12483 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
12484 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
12485
12486 /* Controls for GPIO pins, assuming they are configured as outputs */
12487 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
12488 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
12489 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
12490 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
12491
12492 /* Switches to allow the digital SPDIF output pin to be enabled.
12493 * The ALC268 does not have an SPDIF input.
12494 */
12495 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
12496
12497 /* A switch allowing EAPD to be enabled. Some laptops seem to use
12498 * this output to turn on an external amplifier.
12499 */
12500 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
12501 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
12502
12503 { } /* end */
12504};
12505#endif
12506
Kailang Yanga361d842007-06-05 12:30:55 +020012507/* create input playback/capture controls for the given pin */
12508static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
12509 const char *ctlname, int idx)
12510{
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012511 hda_nid_t dac;
Kailang Yanga361d842007-06-05 12:30:55 +020012512 int err;
12513
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012514 switch (nid) {
12515 case 0x14:
12516 case 0x16:
12517 dac = 0x02;
12518 break;
12519 case 0x15:
12520 dac = 0x03;
12521 break;
12522 default:
12523 return 0;
12524 }
12525 if (spec->multiout.dac_nids[0] != dac &&
12526 spec->multiout.dac_nids[1] != dac) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020012527 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012528 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
Kailang Yanga361d842007-06-05 12:30:55 +020012529 HDA_OUTPUT));
12530 if (err < 0)
12531 return err;
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012532 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
12533 }
12534
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012535 if (nid != 0x16)
Takashi Iwai0afe5f82009-10-02 09:20:00 +020012536 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Kailang Yanga361d842007-06-05 12:30:55 +020012537 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012538 else /* mono */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020012539 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012540 HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020012541 if (err < 0)
12542 return err;
12543 return 0;
12544}
12545
12546/* add playback controls from the parsed DAC table */
12547static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
12548 const struct auto_pin_cfg *cfg)
12549{
12550 hda_nid_t nid;
12551 int err;
12552
Kailang Yanga361d842007-06-05 12:30:55 +020012553 spec->multiout.dac_nids = spec->private_dac_nids;
Kailang Yanga361d842007-06-05 12:30:55 +020012554
12555 nid = cfg->line_out_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012556 if (nid) {
12557 const char *name;
12558 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
12559 name = "Speaker";
12560 else
12561 name = "Front";
12562 err = alc268_new_analog_output(spec, nid, name, 0);
12563 if (err < 0)
12564 return err;
12565 }
Kailang Yanga361d842007-06-05 12:30:55 +020012566
12567 nid = cfg->speaker_pins[0];
12568 if (nid == 0x1d) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020012569 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Speaker",
Kailang Yanga361d842007-06-05 12:30:55 +020012570 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
12571 if (err < 0)
12572 return err;
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012573 } else {
12574 err = alc268_new_analog_output(spec, nid, "Speaker", 0);
12575 if (err < 0)
12576 return err;
Kailang Yanga361d842007-06-05 12:30:55 +020012577 }
12578 nid = cfg->hp_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012579 if (nid) {
12580 err = alc268_new_analog_output(spec, nid, "Headphone", 0);
12581 if (err < 0)
12582 return err;
12583 }
Kailang Yanga361d842007-06-05 12:30:55 +020012584
12585 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
12586 if (nid == 0x16) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020012587 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, "Mono",
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012588 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020012589 if (err < 0)
12590 return err;
12591 }
Kailang Yangea1fb292008-08-26 12:58:38 +020012592 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020012593}
12594
12595/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020012596static int alc268_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yanga361d842007-06-05 12:30:55 +020012597 const struct auto_pin_cfg *cfg)
12598{
Takashi Iwai05f5f472009-08-25 13:10:18 +020012599 return alc_auto_create_input_ctls(codec, cfg, 0, 0x23, 0x24);
Kailang Yanga361d842007-06-05 12:30:55 +020012600}
12601
Takashi Iwaie9af4f32009-08-29 23:23:08 +020012602static void alc268_auto_set_output_and_unmute(struct hda_codec *codec,
12603 hda_nid_t nid, int pin_type)
12604{
12605 int idx;
12606
12607 alc_set_pin_output(codec, nid, pin_type);
12608 if (nid == 0x14 || nid == 0x16)
12609 idx = 0;
12610 else
12611 idx = 1;
12612 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
12613}
12614
12615static void alc268_auto_init_multi_out(struct hda_codec *codec)
12616{
12617 struct alc_spec *spec = codec->spec;
12618 hda_nid_t nid = spec->autocfg.line_out_pins[0];
12619 if (nid) {
12620 int pin_type = get_pin_type(spec->autocfg.line_out_type);
12621 alc268_auto_set_output_and_unmute(codec, nid, pin_type);
12622 }
12623}
12624
12625static void alc268_auto_init_hp_out(struct hda_codec *codec)
12626{
12627 struct alc_spec *spec = codec->spec;
12628 hda_nid_t pin;
12629
12630 pin = spec->autocfg.hp_pins[0];
12631 if (pin)
12632 alc268_auto_set_output_and_unmute(codec, pin, PIN_HP);
12633 pin = spec->autocfg.speaker_pins[0];
12634 if (pin)
12635 alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT);
12636}
12637
Kailang Yanga361d842007-06-05 12:30:55 +020012638static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
12639{
12640 struct alc_spec *spec = codec->spec;
12641 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
12642 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
12643 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
12644 unsigned int dac_vol1, dac_vol2;
12645
Takashi Iwaie9af4f32009-08-29 23:23:08 +020012646 if (line_nid == 0x1d || speaker_nid == 0x1d) {
Kailang Yanga361d842007-06-05 12:30:55 +020012647 snd_hda_codec_write(codec, speaker_nid, 0,
12648 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020012649 /* mute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020012650 snd_hda_codec_write(codec, 0x0f, 0,
12651 AC_VERB_SET_AMP_GAIN_MUTE,
12652 AMP_IN_UNMUTE(1));
12653 snd_hda_codec_write(codec, 0x10, 0,
12654 AC_VERB_SET_AMP_GAIN_MUTE,
12655 AMP_IN_UNMUTE(1));
12656 } else {
Takashi Iwaie9af4f32009-08-29 23:23:08 +020012657 /* unmute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020012658 snd_hda_codec_write(codec, 0x0f, 0,
12659 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
12660 snd_hda_codec_write(codec, 0x10, 0,
12661 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
12662 }
12663
12664 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020012665 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020012666 dac_vol2 = AMP_OUT_ZERO;
12667 else if (line_nid == 0x15)
12668 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020012669 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020012670 dac_vol2 = AMP_OUT_ZERO;
12671 else if (hp_nid == 0x15)
12672 dac_vol1 = AMP_OUT_ZERO;
12673 if (line_nid != 0x16 || hp_nid != 0x16 ||
12674 spec->autocfg.line_out_pins[1] != 0x16 ||
12675 spec->autocfg.line_out_pins[2] != 0x16)
12676 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
12677
12678 snd_hda_codec_write(codec, 0x02, 0,
12679 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
12680 snd_hda_codec_write(codec, 0x03, 0,
12681 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
12682}
12683
Sasha Alexandrdef319f2009-06-16 16:00:15 -040012684/* pcm configuration: identical with ALC880 */
Kailang Yanga361d842007-06-05 12:30:55 +020012685#define alc268_pcm_analog_playback alc880_pcm_analog_playback
12686#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010012687#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020012688#define alc268_pcm_digital_playback alc880_pcm_digital_playback
12689
12690/*
12691 * BIOS auto configuration
12692 */
12693static int alc268_parse_auto_config(struct hda_codec *codec)
12694{
12695 struct alc_spec *spec = codec->spec;
12696 int err;
12697 static hda_nid_t alc268_ignore[] = { 0 };
12698
12699 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12700 alc268_ignore);
12701 if (err < 0)
12702 return err;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012703 if (!spec->autocfg.line_outs) {
12704 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
12705 spec->multiout.max_channels = 2;
12706 spec->no_analog = 1;
12707 goto dig_only;
12708 }
Kailang Yanga361d842007-06-05 12:30:55 +020012709 return 0; /* can't find valid BIOS pin config */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012710 }
Kailang Yanga361d842007-06-05 12:30:55 +020012711 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
12712 if (err < 0)
12713 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020012714 err = alc268_auto_create_input_ctls(codec, &spec->autocfg);
Kailang Yanga361d842007-06-05 12:30:55 +020012715 if (err < 0)
12716 return err;
12717
12718 spec->multiout.max_channels = 2;
12719
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012720 dig_only:
Kailang Yanga361d842007-06-05 12:30:55 +020012721 /* digital only support output */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012722 if (spec->autocfg.dig_outs) {
Kailang Yanga361d842007-06-05 12:30:55 +020012723 spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012724 spec->dig_out_type = spec->autocfg.dig_out_type[0];
12725 }
Takashi Iwai603c4012008-07-30 15:01:44 +020012726 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012727 add_mixer(spec, spec->kctls.list);
Kailang Yanga361d842007-06-05 12:30:55 +020012728
Takashi Iwai892981f2009-03-02 08:04:35 +010012729 if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012730 add_mixer(spec, alc268_beep_mixer);
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012731
Takashi Iwaid88897e2008-10-31 15:01:37 +010012732 add_verb(spec, alc268_volume_init_verbs);
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030012733 spec->num_mux_defs = 2;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020012734 spec->input_mux = &spec->private_imux[0];
Kailang Yanga361d842007-06-05 12:30:55 +020012735
Takashi Iwai776e1842007-08-29 15:07:11 +020012736 err = alc_auto_add_mic_boost(codec);
12737 if (err < 0)
12738 return err;
12739
Takashi Iwai1d955eb2009-06-29 11:33:53 +020012740 alc_ssid_check(codec, 0x15, 0x1b, 0x14);
12741
Kailang Yanga361d842007-06-05 12:30:55 +020012742 return 1;
12743}
12744
Kailang Yanga361d842007-06-05 12:30:55 +020012745#define alc268_auto_init_analog_input alc882_auto_init_analog_input
12746
12747/* init callback for auto-configuration model -- overriding the default init */
12748static void alc268_auto_init(struct hda_codec *codec)
12749{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012750 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020012751 alc268_auto_init_multi_out(codec);
12752 alc268_auto_init_hp_out(codec);
12753 alc268_auto_init_mono_speaker_out(codec);
12754 alc268_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012755 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020012756 alc_inithook(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020012757}
12758
12759/*
12760 * configuration and preset
12761 */
12762static const char *alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012763 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020012764 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020012765 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020012766 [ALC268_ACER] = "acer",
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012767 [ALC268_ACER_DMIC] = "acer-dmic",
Kailang Yang8ef355d2008-08-26 13:10:22 +020012768 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012769 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012770 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010012771#ifdef CONFIG_SND_DEBUG
12772 [ALC268_TEST] = "test",
12773#endif
Kailang Yanga361d842007-06-05 12:30:55 +020012774 [ALC268_AUTO] = "auto",
12775};
12776
12777static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020012778 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012779 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010012780 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012781 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010012782 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020012783 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
12784 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012785 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Daniel T Chena1bf8082009-11-01 18:32:29 -050012786 SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0,
12787 "Dell Inspiron Mini9/Vostro A90", ALC268_DELL),
Takashi Iwai33d78672009-09-08 11:03:41 +020012788 /* almost compatible with toshiba but with optional digital outs;
12789 * auto-probing seems working fine
12790 */
Takashi Iwai8871e5b2009-06-02 01:02:50 +020012791 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series",
Takashi Iwai33d78672009-09-08 11:03:41 +020012792 ALC268_AUTO),
Kailang Yanga361d842007-06-05 12:30:55 +020012793 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020012794 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Tony Vroon378bd6a2008-06-04 12:08:30 +020012795 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020012796 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012797 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020012798 SND_PCI_QUIRK(0x1854, 0x1775, "LG R510", ALC268_DELL),
Kailang Yanga361d842007-06-05 12:30:55 +020012799 {}
12800};
12801
Takashi Iwai3abf2f32009-08-19 20:05:02 +020012802/* Toshiba laptops have no unique PCI SSID but only codec SSID */
12803static struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
12804 SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO),
12805 SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO),
12806 SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
12807 ALC268_TOSHIBA),
12808 {}
12809};
12810
Kailang Yanga361d842007-06-05 12:30:55 +020012811static struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012812 [ALC267_QUANTA_IL1] = {
Takashi Iwaifdbc6622009-08-19 00:18:10 +020012813 .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer,
12814 alc268_capture_nosrc_mixer },
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012815 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12816 alc267_quanta_il1_verbs },
12817 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12818 .dac_nids = alc268_dac_nids,
12819 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12820 .adc_nids = alc268_adc_nids_alt,
12821 .hp_nid = 0x03,
12822 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12823 .channel_mode = alc268_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012824 .unsol_event = alc_sku_unsol_event,
12825 .setup = alc267_quanta_il1_setup,
12826 .init_hook = alc_inithook,
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012827 },
Kailang Yanga361d842007-06-05 12:30:55 +020012828 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012829 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
12830 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020012831 .init_verbs = { alc268_base_init_verbs },
12832 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12833 .dac_nids = alc268_dac_nids,
12834 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12835 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010012836 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020012837 .hp_nid = 0x03,
12838 .dig_out_nid = ALC268_DIGOUT_NID,
12839 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12840 .channel_mode = alc268_modes,
12841 .input_mux = &alc268_capture_source,
12842 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020012843 [ALC268_TOSHIBA] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020012844 .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012845 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020012846 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12847 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020012848 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12849 .dac_nids = alc268_dac_nids,
12850 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12851 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010012852 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020012853 .hp_nid = 0x03,
12854 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12855 .channel_mode = alc268_modes,
12856 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020012857 .unsol_event = alc268_toshiba_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012858 .setup = alc268_toshiba_setup,
12859 .init_hook = alc268_toshiba_automute,
Takashi Iwaid2738092007-08-16 14:59:45 +020012860 },
12861 [ALC268_ACER] = {
Takashi Iwai432fd132009-09-30 08:13:44 +020012862 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012863 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020012864 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12865 alc268_acer_verbs },
12866 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12867 .dac_nids = alc268_dac_nids,
12868 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12869 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010012870 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020012871 .hp_nid = 0x02,
12872 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12873 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012874 .input_mux = &alc268_acer_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020012875 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020012876 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020012877 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012878 [ALC268_ACER_DMIC] = {
12879 .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
12880 alc268_beep_mixer },
12881 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12882 alc268_acer_verbs },
12883 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12884 .dac_nids = alc268_dac_nids,
12885 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12886 .adc_nids = alc268_adc_nids_alt,
12887 .capsrc_nids = alc268_capsrc_nids,
12888 .hp_nid = 0x02,
12889 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12890 .channel_mode = alc268_modes,
12891 .input_mux = &alc268_acer_dmic_capture_source,
12892 .unsol_event = alc268_acer_unsol_event,
12893 .init_hook = alc268_acer_init_hook,
12894 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020012895 [ALC268_ACER_ASPIRE_ONE] = {
12896 .mixers = { alc268_acer_aspire_one_mixer,
Takashi Iwai22971e32009-02-10 11:56:44 +010012897 alc268_beep_mixer,
Takashi Iwaifdbc6622009-08-19 00:18:10 +020012898 alc268_capture_nosrc_mixer },
Kailang Yang8ef355d2008-08-26 13:10:22 +020012899 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12900 alc268_acer_aspire_one_verbs },
12901 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12902 .dac_nids = alc268_dac_nids,
12903 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12904 .adc_nids = alc268_adc_nids_alt,
12905 .capsrc_nids = alc268_capsrc_nids,
12906 .hp_nid = 0x03,
12907 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12908 .channel_mode = alc268_modes,
Kailang Yang8ef355d2008-08-26 13:10:22 +020012909 .unsol_event = alc268_acer_lc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012910 .setup = alc268_acer_lc_setup,
Kailang Yang8ef355d2008-08-26 13:10:22 +020012911 .init_hook = alc268_acer_lc_init_hook,
12912 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012913 [ALC268_DELL] = {
Takashi Iwaifdbc6622009-08-19 00:18:10 +020012914 .mixers = { alc268_dell_mixer, alc268_beep_mixer,
12915 alc268_capture_nosrc_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012916 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12917 alc268_dell_verbs },
12918 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12919 .dac_nids = alc268_dac_nids,
Takashi Iwaifdbc6622009-08-19 00:18:10 +020012920 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12921 .adc_nids = alc268_adc_nids_alt,
12922 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012923 .hp_nid = 0x02,
12924 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12925 .channel_mode = alc268_modes,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012926 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012927 .setup = alc268_dell_setup,
12928 .init_hook = alc_inithook,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012929 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012930 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012931 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
12932 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012933 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12934 alc268_toshiba_verbs },
12935 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12936 .dac_nids = alc268_dac_nids,
12937 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12938 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010012939 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012940 .hp_nid = 0x03,
12941 .dig_out_nid = ALC268_DIGOUT_NID,
12942 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12943 .channel_mode = alc268_modes,
12944 .input_mux = &alc268_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012945 .setup = alc268_toshiba_setup,
12946 .init_hook = alc268_toshiba_automute,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012947 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010012948#ifdef CONFIG_SND_DEBUG
12949 [ALC268_TEST] = {
12950 .mixers = { alc268_test_mixer, alc268_capture_mixer },
12951 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12952 alc268_volume_init_verbs },
12953 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12954 .dac_nids = alc268_dac_nids,
12955 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12956 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010012957 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010012958 .hp_nid = 0x03,
12959 .dig_out_nid = ALC268_DIGOUT_NID,
12960 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12961 .channel_mode = alc268_modes,
12962 .input_mux = &alc268_capture_source,
12963 },
12964#endif
Kailang Yanga361d842007-06-05 12:30:55 +020012965};
12966
12967static int patch_alc268(struct hda_codec *codec)
12968{
12969 struct alc_spec *spec;
12970 int board_config;
Takashi Iwai22971e32009-02-10 11:56:44 +010012971 int i, has_beep, err;
Kailang Yanga361d842007-06-05 12:30:55 +020012972
12973 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
12974 if (spec == NULL)
12975 return -ENOMEM;
12976
12977 codec->spec = spec;
12978
12979 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
12980 alc268_models,
12981 alc268_cfg_tbl);
12982
Takashi Iwai3abf2f32009-08-19 20:05:02 +020012983 if (board_config < 0 || board_config >= ALC268_MODEL_LAST)
12984 board_config = snd_hda_check_board_codec_sid_config(codec,
12985 ALC882_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl);
12986
Kailang Yanga361d842007-06-05 12:30:55 +020012987 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020012988 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
12989 codec->chip_name);
Kailang Yanga361d842007-06-05 12:30:55 +020012990 board_config = ALC268_AUTO;
12991 }
12992
12993 if (board_config == ALC268_AUTO) {
12994 /* automatic parse from the BIOS config */
12995 err = alc268_parse_auto_config(codec);
12996 if (err < 0) {
12997 alc_free(codec);
12998 return err;
12999 } else if (!err) {
13000 printk(KERN_INFO
13001 "hda_codec: Cannot set up configuration "
13002 "from BIOS. Using base mode...\n");
13003 board_config = ALC268_3ST;
13004 }
13005 }
13006
13007 if (board_config != ALC268_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020013008 setup_preset(codec, &alc268_presets[board_config]);
Kailang Yanga361d842007-06-05 12:30:55 +020013009
Kailang Yanga361d842007-06-05 12:30:55 +020013010 spec->stream_analog_playback = &alc268_pcm_analog_playback;
13011 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010013012 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020013013
Kailang Yanga361d842007-06-05 12:30:55 +020013014 spec->stream_digital_playback = &alc268_pcm_digital_playback;
13015
Takashi Iwai22971e32009-02-10 11:56:44 +010013016 has_beep = 0;
13017 for (i = 0; i < spec->num_mixers; i++) {
13018 if (spec->mixers[i] == alc268_beep_mixer) {
13019 has_beep = 1;
13020 break;
13021 }
13022 }
13023
13024 if (has_beep) {
13025 err = snd_hda_attach_beep_device(codec, 0x1);
13026 if (err < 0) {
13027 alc_free(codec);
13028 return err;
13029 }
13030 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
13031 /* override the amp caps for beep generator */
13032 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013033 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
13034 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
13035 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
13036 (0 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwai22971e32009-02-10 11:56:44 +010013037 }
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013038
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013039 if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013040 /* check whether NID 0x07 is valid */
13041 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwai85860c02008-02-19 15:00:15 +010013042 int i;
Kailang Yanga361d842007-06-05 12:30:55 +020013043
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020013044 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013045 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020013046 wcap = get_wcaps_type(wcap);
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013047 if (spec->auto_mic ||
13048 wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013049 spec->adc_nids = alc268_adc_nids_alt;
13050 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020013051 if (spec->auto_mic)
13052 fixup_automic_adc(codec);
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013053 if (spec->auto_mic || spec->input_mux->num_items == 1)
13054 add_mixer(spec, alc268_capture_nosrc_mixer);
13055 else
13056 add_mixer(spec, alc268_capture_alt_mixer);
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013057 } else {
13058 spec->adc_nids = alc268_adc_nids;
13059 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
Takashi Iwaid88897e2008-10-31 15:01:37 +010013060 add_mixer(spec, alc268_capture_mixer);
Kailang Yanga361d842007-06-05 12:30:55 +020013061 }
Takashi Iwai85860c02008-02-19 15:00:15 +010013062 /* set default input source */
13063 for (i = 0; i < spec->num_adc_nids; i++)
13064 snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
13065 0, AC_VERB_SET_CONNECT_SEL,
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030013066 i < spec->num_mux_defs ?
13067 spec->input_mux[i].items[0].index :
Takashi Iwai85860c02008-02-19 15:00:15 +010013068 spec->input_mux->items[0].index);
Kailang Yanga361d842007-06-05 12:30:55 +020013069 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010013070
13071 spec->vmaster_nid = 0x02;
13072
Kailang Yanga361d842007-06-05 12:30:55 +020013073 codec->patch_ops = alc_patch_ops;
13074 if (board_config == ALC268_AUTO)
13075 spec->init_hook = alc268_auto_init;
Kailang Yangea1fb292008-08-26 12:58:38 +020013076
Takashi Iwaidaead532008-11-28 12:55:36 +010013077 codec->proc_widget_hook = print_realtek_coef;
13078
Kailang Yanga361d842007-06-05 12:30:55 +020013079 return 0;
13080}
13081
13082/*
Kailang Yangf6a92242007-12-13 16:52:54 +010013083 * ALC269 channel source setting (2 channel)
13084 */
13085#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
13086
13087#define alc269_dac_nids alc260_dac_nids
13088
13089static hda_nid_t alc269_adc_nids[1] = {
13090 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020013091 0x08,
13092};
13093
Takashi Iwaie01bf502008-08-21 16:25:07 +020013094static hda_nid_t alc269_capsrc_nids[1] = {
13095 0x23,
13096};
13097
13098/* NOTE: ADC2 (0x07) is connected from a recording *MIXER* (0x24),
13099 * not a mux!
13100 */
13101
Kailang Yangf6a92242007-12-13 16:52:54 +010013102#define alc269_modes alc260_modes
13103#define alc269_capture_source alc880_lg_lw_capture_source
13104
13105static struct snd_kcontrol_new alc269_base_mixer[] = {
13106 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13107 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13108 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13109 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13110 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13111 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13112 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13113 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13114 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
13115 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
13116 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
13117 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
13118 { } /* end */
13119};
13120
Kailang Yang60db6b52008-08-26 13:13:00 +020013121static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
13122 /* output mixer control */
13123 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13124 {
13125 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13126 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010013127 .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
Kailang Yang60db6b52008-08-26 13:13:00 +020013128 .info = snd_hda_mixer_amp_switch_info,
13129 .get = snd_hda_mixer_amp_switch_get,
13130 .put = alc268_acer_master_sw_put,
13131 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13132 },
13133 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13134 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13135 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13136 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13137 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
13138 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020013139 { }
13140};
13141
Tony Vroon64154832008-11-06 15:08:49 +000013142static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
13143 /* output mixer control */
13144 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13145 {
13146 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13147 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010013148 .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
Tony Vroon64154832008-11-06 15:08:49 +000013149 .info = snd_hda_mixer_amp_switch_info,
13150 .get = snd_hda_mixer_amp_switch_get,
13151 .put = alc268_acer_master_sw_put,
13152 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13153 },
13154 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13155 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13156 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13157 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13158 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
13159 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
13160 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
13161 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
13162 HDA_CODEC_VOLUME("Dock Mic Boost", 0x1b, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000013163 { }
13164};
13165
Kailang Yangf53281e2008-07-18 12:36:43 +020013166static struct snd_kcontrol_new alc269_eeepc_mixer[] = {
Takashi Iwaiaa202452009-07-03 15:00:54 +020013167 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010013168 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwaiaa202452009-07-03 15:00:54 +020013169 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010013170 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yangf53281e2008-07-18 12:36:43 +020013171 { } /* end */
13172};
13173
Kailang Yangf6a92242007-12-13 16:52:54 +010013174/* capture mixer elements */
Kailang Yangf53281e2008-07-18 12:36:43 +020013175static struct snd_kcontrol_new alc269_epc_capture_mixer[] = {
13176 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
13177 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Takashi Iwai26f5df22008-11-03 17:39:46 +010013178 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13179 { } /* end */
13180};
13181
13182/* FSC amilo */
Takashi Iwaiaa202452009-07-03 15:00:54 +020013183#define alc269_fujitsu_mixer alc269_eeepc_mixer
Kailang Yangf53281e2008-07-18 12:36:43 +020013184
Kailang Yang60db6b52008-08-26 13:13:00 +020013185static struct hda_verb alc269_quanta_fl1_verbs[] = {
13186 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13187 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13188 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13189 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13190 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13191 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13192 { }
13193};
13194
Tony Vroon64154832008-11-06 15:08:49 +000013195static struct hda_verb alc269_lifebook_verbs[] = {
13196 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13197 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
13198 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13199 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13200 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13201 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13202 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13203 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13204 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13205 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13206 { }
13207};
13208
Kailang Yang60db6b52008-08-26 13:13:00 +020013209/* toggle speaker-output according to the hp-jack state */
13210static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
13211{
13212 unsigned int present;
13213 unsigned char bits;
13214
Wu Fengguang864f92b2009-11-18 12:38:02 +080013215 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yang60db6b52008-08-26 13:13:00 +020013216 bits = present ? AMP_IN_MUTE(0) : 0;
13217 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
13218 AMP_IN_MUTE(0), bits);
13219 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
13220 AMP_IN_MUTE(0), bits);
13221
13222 snd_hda_codec_write(codec, 0x20, 0,
13223 AC_VERB_SET_COEF_INDEX, 0x0c);
13224 snd_hda_codec_write(codec, 0x20, 0,
13225 AC_VERB_SET_PROC_COEF, 0x680);
13226
13227 snd_hda_codec_write(codec, 0x20, 0,
13228 AC_VERB_SET_COEF_INDEX, 0x0c);
13229 snd_hda_codec_write(codec, 0x20, 0,
13230 AC_VERB_SET_PROC_COEF, 0x480);
13231}
13232
Tony Vroon64154832008-11-06 15:08:49 +000013233/* toggle speaker-output according to the hp-jacks state */
13234static void alc269_lifebook_speaker_automute(struct hda_codec *codec)
13235{
13236 unsigned int present;
13237 unsigned char bits;
13238
13239 /* Check laptop headphone socket */
Wu Fengguang864f92b2009-11-18 12:38:02 +080013240 present = snd_hda_jack_detect(codec, 0x15);
Tony Vroon64154832008-11-06 15:08:49 +000013241
13242 /* Check port replicator headphone socket */
Wu Fengguang864f92b2009-11-18 12:38:02 +080013243 present |= snd_hda_jack_detect(codec, 0x1a);
Tony Vroon64154832008-11-06 15:08:49 +000013244
13245 bits = present ? AMP_IN_MUTE(0) : 0;
13246 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
13247 AMP_IN_MUTE(0), bits);
13248 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
13249 AMP_IN_MUTE(0), bits);
13250
13251 snd_hda_codec_write(codec, 0x20, 0,
13252 AC_VERB_SET_COEF_INDEX, 0x0c);
13253 snd_hda_codec_write(codec, 0x20, 0,
13254 AC_VERB_SET_PROC_COEF, 0x680);
13255
13256 snd_hda_codec_write(codec, 0x20, 0,
13257 AC_VERB_SET_COEF_INDEX, 0x0c);
13258 snd_hda_codec_write(codec, 0x20, 0,
13259 AC_VERB_SET_PROC_COEF, 0x480);
13260}
13261
Tony Vroon64154832008-11-06 15:08:49 +000013262static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
13263{
13264 unsigned int present_laptop;
13265 unsigned int present_dock;
13266
Wu Fengguang864f92b2009-11-18 12:38:02 +080013267 present_laptop = snd_hda_jack_detect(codec, 0x18);
13268 present_dock = snd_hda_jack_detect(codec, 0x1b);
Tony Vroon64154832008-11-06 15:08:49 +000013269
13270 /* Laptop mic port overrides dock mic port, design decision */
13271 if (present_dock)
13272 snd_hda_codec_write(codec, 0x23, 0,
13273 AC_VERB_SET_CONNECT_SEL, 0x3);
13274 if (present_laptop)
13275 snd_hda_codec_write(codec, 0x23, 0,
13276 AC_VERB_SET_CONNECT_SEL, 0x0);
13277 if (!present_dock && !present_laptop)
13278 snd_hda_codec_write(codec, 0x23, 0,
13279 AC_VERB_SET_CONNECT_SEL, 0x1);
13280}
13281
Kailang Yang60db6b52008-08-26 13:13:00 +020013282static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
13283 unsigned int res)
13284{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013285 switch (res >> 26) {
13286 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020013287 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013288 break;
13289 case ALC880_MIC_EVENT:
13290 alc_mic_automute(codec);
13291 break;
13292 }
Kailang Yang60db6b52008-08-26 13:13:00 +020013293}
13294
Tony Vroon64154832008-11-06 15:08:49 +000013295static void alc269_lifebook_unsol_event(struct hda_codec *codec,
13296 unsigned int res)
13297{
13298 if ((res >> 26) == ALC880_HP_EVENT)
13299 alc269_lifebook_speaker_automute(codec);
13300 if ((res >> 26) == ALC880_MIC_EVENT)
13301 alc269_lifebook_mic_autoswitch(codec);
13302}
13303
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013304static void alc269_quanta_fl1_setup(struct hda_codec *codec)
13305{
13306 struct alc_spec *spec = codec->spec;
13307 spec->ext_mic.pin = 0x18;
13308 spec->ext_mic.mux_idx = 0;
13309 spec->int_mic.pin = 0x19;
13310 spec->int_mic.mux_idx = 1;
13311 spec->auto_mic = 1;
13312}
13313
Kailang Yang60db6b52008-08-26 13:13:00 +020013314static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
13315{
13316 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013317 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020013318}
13319
Tony Vroon64154832008-11-06 15:08:49 +000013320static void alc269_lifebook_init_hook(struct hda_codec *codec)
13321{
13322 alc269_lifebook_speaker_automute(codec);
13323 alc269_lifebook_mic_autoswitch(codec);
13324}
13325
Kailang Yang60db6b52008-08-26 13:13:00 +020013326static struct hda_verb alc269_eeepc_dmic_init_verbs[] = {
13327 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13328 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
13329 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
13330 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
13331 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13332 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13333 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13334 {}
13335};
13336
13337static struct hda_verb alc269_eeepc_amic_init_verbs[] = {
13338 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13339 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
13340 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
13341 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
13342 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13343 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13344 {}
13345};
13346
13347/* toggle speaker-output according to the hp-jack state */
13348static void alc269_speaker_automute(struct hda_codec *codec)
13349{
13350 unsigned int present;
13351 unsigned char bits;
13352
Wu Fengguang864f92b2009-11-18 12:38:02 +080013353 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yang60db6b52008-08-26 13:13:00 +020013354 bits = present ? AMP_IN_MUTE(0) : 0;
13355 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
13356 AMP_IN_MUTE(0), bits);
13357 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
13358 AMP_IN_MUTE(0), bits);
13359}
13360
Kailang Yang60db6b52008-08-26 13:13:00 +020013361/* unsolicited event for HP jack sensing */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013362static void alc269_eeepc_unsol_event(struct hda_codec *codec,
Kailang Yang60db6b52008-08-26 13:13:00 +020013363 unsigned int res)
13364{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013365 switch (res >> 26) {
13366 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020013367 alc269_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013368 break;
13369 case ALC880_MIC_EVENT:
13370 alc_mic_automute(codec);
13371 break;
13372 }
Kailang Yang60db6b52008-08-26 13:13:00 +020013373}
13374
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013375static void alc269_eeepc_dmic_setup(struct hda_codec *codec)
13376{
13377 struct alc_spec *spec = codec->spec;
13378 spec->ext_mic.pin = 0x18;
13379 spec->ext_mic.mux_idx = 0;
13380 spec->int_mic.pin = 0x12;
13381 spec->int_mic.mux_idx = 5;
13382 spec->auto_mic = 1;
13383}
13384
13385static void alc269_eeepc_amic_setup(struct hda_codec *codec)
13386{
13387 struct alc_spec *spec = codec->spec;
13388 spec->ext_mic.pin = 0x18;
13389 spec->ext_mic.mux_idx = 0;
13390 spec->int_mic.pin = 0x19;
13391 spec->int_mic.mux_idx = 1;
13392 spec->auto_mic = 1;
13393}
13394
13395static void alc269_eeepc_inithook(struct hda_codec *codec)
Kailang Yang60db6b52008-08-26 13:13:00 +020013396{
13397 alc269_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013398 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020013399}
13400
Kailang Yangf6a92242007-12-13 16:52:54 +010013401/*
13402 * generic initialization of ADC, input mixers and output mixers
13403 */
13404static struct hda_verb alc269_init_verbs[] = {
13405 /*
13406 * Unmute ADC0 and set the default input to mic-in
13407 */
Kailang Yang60db6b52008-08-26 13:13:00 +020013408 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010013409
13410 /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the
13411 * analog-loopback mixer widget
13412 * Note: PASD motherboards uses the Line In 2 as the input for
13413 * front panel mic (mic 2)
13414 */
13415 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
13416 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13417 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13418 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
13419 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
13420 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
13421
13422 /*
13423 * Set up output mixers (0x0c - 0x0e)
13424 */
13425 /* set vol=0 to output mixers */
13426 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13427 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13428
13429 /* set up input amps for analog loopback */
13430 /* Amp Indices: DAC = 0, mixer = 1 */
13431 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13432 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13433 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13434 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13435 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13436 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13437
13438 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13439 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13440 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13441 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13442 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13443 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13444 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13445
13446 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13447 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13448 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13449 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13450 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13451 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13452 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13453
13454 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
13455 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
13456
13457 /* FIXME: use matrix-type input source selection */
13458 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
13459 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang60db6b52008-08-26 13:13:00 +020013460 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13461 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangf6a92242007-12-13 16:52:54 +010013462 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
13463 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
13464
13465 /* set EAPD */
13466 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
13467 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
13468 { }
13469};
13470
Takashi Iwai9d0b71b2009-08-24 14:10:30 +020013471#define alc269_auto_create_multi_out_ctls \
13472 alc268_auto_create_multi_out_ctls
Takashi Iwai05f5f472009-08-25 13:10:18 +020013473#define alc269_auto_create_input_ctls \
13474 alc268_auto_create_input_ctls
Kailang Yangf6a92242007-12-13 16:52:54 +010013475
13476#ifdef CONFIG_SND_HDA_POWER_SAVE
13477#define alc269_loopbacks alc880_loopbacks
13478#endif
13479
Sasha Alexandrdef319f2009-06-16 16:00:15 -040013480/* pcm configuration: identical with ALC880 */
Kailang Yangf6a92242007-12-13 16:52:54 +010013481#define alc269_pcm_analog_playback alc880_pcm_analog_playback
13482#define alc269_pcm_analog_capture alc880_pcm_analog_capture
13483#define alc269_pcm_digital_playback alc880_pcm_digital_playback
13484#define alc269_pcm_digital_capture alc880_pcm_digital_capture
13485
Takashi Iwaif03d3112009-03-05 14:18:16 +010013486static struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
13487 .substreams = 1,
13488 .channels_min = 2,
13489 .channels_max = 8,
13490 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
13491 /* NID is set in alc_build_pcms */
13492 .ops = {
13493 .open = alc880_playback_pcm_open,
13494 .prepare = alc880_playback_pcm_prepare,
13495 .cleanup = alc880_playback_pcm_cleanup
13496 },
13497};
13498
13499static struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
13500 .substreams = 1,
13501 .channels_min = 2,
13502 .channels_max = 2,
13503 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
13504 /* NID is set in alc_build_pcms */
13505};
13506
Kailang Yangf6a92242007-12-13 16:52:54 +010013507/*
13508 * BIOS auto configuration
13509 */
13510static int alc269_parse_auto_config(struct hda_codec *codec)
13511{
13512 struct alc_spec *spec = codec->spec;
Takashi Iwaicfb9fb52009-02-06 17:34:03 +010013513 int err;
Kailang Yangf6a92242007-12-13 16:52:54 +010013514 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
13515
13516 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13517 alc269_ignore);
13518 if (err < 0)
13519 return err;
13520
13521 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
13522 if (err < 0)
13523 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020013524 err = alc269_auto_create_input_ctls(codec, &spec->autocfg);
Kailang Yangf6a92242007-12-13 16:52:54 +010013525 if (err < 0)
13526 return err;
13527
13528 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
13529
Takashi Iwai0852d7a2009-02-11 11:35:15 +010013530 if (spec->autocfg.dig_outs)
Kailang Yangf6a92242007-12-13 16:52:54 +010013531 spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
13532
Takashi Iwai603c4012008-07-30 15:01:44 +020013533 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013534 add_mixer(spec, spec->kctls.list);
Kailang Yangf6a92242007-12-13 16:52:54 +010013535
Takashi Iwaid88897e2008-10-31 15:01:37 +010013536 add_verb(spec, alc269_init_verbs);
Kailang Yangf6a92242007-12-13 16:52:54 +010013537 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020013538 spec->input_mux = &spec->private_imux[0];
Takashi Iwaie01bf502008-08-21 16:25:07 +020013539 /* set default input source */
13540 snd_hda_codec_write_cache(codec, alc269_capsrc_nids[0],
13541 0, AC_VERB_SET_CONNECT_SEL,
13542 spec->input_mux->items[0].index);
Kailang Yangf6a92242007-12-13 16:52:54 +010013543
13544 err = alc_auto_add_mic_boost(codec);
13545 if (err < 0)
13546 return err;
13547
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013548 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020013549 set_capture_mixer(codec);
Kailang Yangf53281e2008-07-18 12:36:43 +020013550
Takashi Iwai1d955eb2009-06-29 11:33:53 +020013551 alc_ssid_check(codec, 0x15, 0x1b, 0x14);
13552
Kailang Yangf6a92242007-12-13 16:52:54 +010013553 return 1;
13554}
13555
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013556#define alc269_auto_init_multi_out alc268_auto_init_multi_out
13557#define alc269_auto_init_hp_out alc268_auto_init_hp_out
Kailang Yangf6a92242007-12-13 16:52:54 +010013558#define alc269_auto_init_analog_input alc882_auto_init_analog_input
13559
13560
13561/* init callback for auto-configuration model -- overriding the default init */
13562static void alc269_auto_init(struct hda_codec *codec)
13563{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013564 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010013565 alc269_auto_init_multi_out(codec);
13566 alc269_auto_init_hp_out(codec);
13567 alc269_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013568 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020013569 alc_inithook(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010013570}
13571
13572/*
13573 * configuration and preset
13574 */
13575static const char *alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020013576 [ALC269_BASIC] = "basic",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020013577 [ALC269_QUANTA_FL1] = "quanta",
13578 [ALC269_ASUS_EEEPC_P703] = "eeepc-p703",
Takashi Iwai26f5df22008-11-03 17:39:46 +010013579 [ALC269_ASUS_EEEPC_P901] = "eeepc-p901",
Tony Vroon64154832008-11-06 15:08:49 +000013580 [ALC269_FUJITSU] = "fujitsu",
Takashi Iwai3d3792c2009-09-11 07:50:47 +020013581 [ALC269_LIFEBOOK] = "lifebook",
13582 [ALC269_AUTO] = "auto",
Kailang Yangf6a92242007-12-13 16:52:54 +010013583};
13584
13585static struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020013586 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangf53281e2008-07-18 12:36:43 +020013587 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
13588 ALC269_ASUS_EEEPC_P703),
Kailang Yang622e84c2009-04-21 07:39:04 +020013589 SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_ASUS_EEEPC_P703),
13590 SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_ASUS_EEEPC_P703),
13591 SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_ASUS_EEEPC_P703),
13592 SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_ASUS_EEEPC_P703),
13593 SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_ASUS_EEEPC_P703),
13594 SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_ASUS_EEEPC_P703),
Kailang Yangf53281e2008-07-18 12:36:43 +020013595 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
13596 ALC269_ASUS_EEEPC_P901),
Kailang Yang60db6b52008-08-26 13:13:00 +020013597 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
13598 ALC269_ASUS_EEEPC_P901),
Kailang Yang622e84c2009-04-21 07:39:04 +020013599 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_ASUS_EEEPC_P901),
Takashi Iwai26f5df22008-11-03 17:39:46 +010013600 SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
Tony Vroon64154832008-11-06 15:08:49 +000013601 SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
Kailang Yangf6a92242007-12-13 16:52:54 +010013602 {}
13603};
13604
13605static struct alc_config_preset alc269_presets[] = {
13606 [ALC269_BASIC] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010013607 .mixers = { alc269_base_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010013608 .init_verbs = { alc269_init_verbs },
13609 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13610 .dac_nids = alc269_dac_nids,
13611 .hp_nid = 0x03,
13612 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13613 .channel_mode = alc269_modes,
13614 .input_mux = &alc269_capture_source,
13615 },
Kailang Yang60db6b52008-08-26 13:13:00 +020013616 [ALC269_QUANTA_FL1] = {
13617 .mixers = { alc269_quanta_fl1_mixer },
13618 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
13619 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13620 .dac_nids = alc269_dac_nids,
13621 .hp_nid = 0x03,
13622 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13623 .channel_mode = alc269_modes,
13624 .input_mux = &alc269_capture_source,
13625 .unsol_event = alc269_quanta_fl1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013626 .setup = alc269_quanta_fl1_setup,
Kailang Yang60db6b52008-08-26 13:13:00 +020013627 .init_hook = alc269_quanta_fl1_init_hook,
13628 },
Kailang Yangf53281e2008-07-18 12:36:43 +020013629 [ALC269_ASUS_EEEPC_P703] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010013630 .mixers = { alc269_eeepc_mixer },
13631 .cap_mixer = alc269_epc_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020013632 .init_verbs = { alc269_init_verbs,
13633 alc269_eeepc_amic_init_verbs },
13634 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13635 .dac_nids = alc269_dac_nids,
13636 .hp_nid = 0x03,
13637 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13638 .channel_mode = alc269_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013639 .unsol_event = alc269_eeepc_unsol_event,
13640 .setup = alc269_eeepc_amic_setup,
13641 .init_hook = alc269_eeepc_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020013642 },
13643 [ALC269_ASUS_EEEPC_P901] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010013644 .mixers = { alc269_eeepc_mixer },
13645 .cap_mixer = alc269_epc_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020013646 .init_verbs = { alc269_init_verbs,
13647 alc269_eeepc_dmic_init_verbs },
13648 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13649 .dac_nids = alc269_dac_nids,
13650 .hp_nid = 0x03,
13651 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13652 .channel_mode = alc269_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013653 .unsol_event = alc269_eeepc_unsol_event,
13654 .setup = alc269_eeepc_dmic_setup,
13655 .init_hook = alc269_eeepc_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020013656 },
Takashi Iwai26f5df22008-11-03 17:39:46 +010013657 [ALC269_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010013658 .mixers = { alc269_fujitsu_mixer },
Takashi Iwai26f5df22008-11-03 17:39:46 +010013659 .cap_mixer = alc269_epc_capture_mixer,
13660 .init_verbs = { alc269_init_verbs,
13661 alc269_eeepc_dmic_init_verbs },
13662 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13663 .dac_nids = alc269_dac_nids,
13664 .hp_nid = 0x03,
13665 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13666 .channel_mode = alc269_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013667 .unsol_event = alc269_eeepc_unsol_event,
13668 .setup = alc269_eeepc_dmic_setup,
13669 .init_hook = alc269_eeepc_inithook,
Takashi Iwai26f5df22008-11-03 17:39:46 +010013670 },
Tony Vroon64154832008-11-06 15:08:49 +000013671 [ALC269_LIFEBOOK] = {
13672 .mixers = { alc269_lifebook_mixer },
13673 .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
13674 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13675 .dac_nids = alc269_dac_nids,
13676 .hp_nid = 0x03,
13677 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13678 .channel_mode = alc269_modes,
13679 .input_mux = &alc269_capture_source,
13680 .unsol_event = alc269_lifebook_unsol_event,
13681 .init_hook = alc269_lifebook_init_hook,
13682 },
Kailang Yangf6a92242007-12-13 16:52:54 +010013683};
13684
13685static int patch_alc269(struct hda_codec *codec)
13686{
13687 struct alc_spec *spec;
13688 int board_config;
13689 int err;
13690
13691 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
13692 if (spec == NULL)
13693 return -ENOMEM;
13694
13695 codec->spec = spec;
13696
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020013697 alc_fix_pll_init(codec, 0x20, 0x04, 15);
13698
Kailang Yang274693f2009-12-03 10:07:50 +010013699 if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){
13700 kfree(codec->chip_name);
13701 codec->chip_name = kstrdup("ALC259", GFP_KERNEL);
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010013702 if (!codec->chip_name) {
13703 alc_free(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010013704 return -ENOMEM;
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010013705 }
Kailang Yang274693f2009-12-03 10:07:50 +010013706 }
13707
Kailang Yangf6a92242007-12-13 16:52:54 +010013708 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
13709 alc269_models,
13710 alc269_cfg_tbl);
13711
13712 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020013713 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
13714 codec->chip_name);
Kailang Yangf6a92242007-12-13 16:52:54 +010013715 board_config = ALC269_AUTO;
13716 }
13717
13718 if (board_config == ALC269_AUTO) {
13719 /* automatic parse from the BIOS config */
13720 err = alc269_parse_auto_config(codec);
13721 if (err < 0) {
13722 alc_free(codec);
13723 return err;
13724 } else if (!err) {
13725 printk(KERN_INFO
13726 "hda_codec: Cannot set up configuration "
13727 "from BIOS. Using base mode...\n");
13728 board_config = ALC269_BASIC;
13729 }
13730 }
13731
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090013732 err = snd_hda_attach_beep_device(codec, 0x1);
13733 if (err < 0) {
13734 alc_free(codec);
13735 return err;
13736 }
13737
Kailang Yangf6a92242007-12-13 16:52:54 +010013738 if (board_config != ALC269_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020013739 setup_preset(codec, &alc269_presets[board_config]);
Kailang Yangf6a92242007-12-13 16:52:54 +010013740
Takashi Iwaif03d3112009-03-05 14:18:16 +010013741 if (codec->subsystem_id == 0x17aa3bf8) {
13742 /* Due to a hardware problem on Lenovo Ideadpad, we need to
13743 * fix the sample rate of analog I/O to 44.1kHz
13744 */
13745 spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
13746 spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
13747 } else {
13748 spec->stream_analog_playback = &alc269_pcm_analog_playback;
13749 spec->stream_analog_capture = &alc269_pcm_analog_capture;
13750 }
Kailang Yangf6a92242007-12-13 16:52:54 +010013751 spec->stream_digital_playback = &alc269_pcm_digital_playback;
13752 spec->stream_digital_capture = &alc269_pcm_digital_capture;
13753
13754 spec->adc_nids = alc269_adc_nids;
13755 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
Takashi Iwaie01bf502008-08-21 16:25:07 +020013756 spec->capsrc_nids = alc269_capsrc_nids;
Takashi Iwaif9e336f2008-10-31 16:37:07 +010013757 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020013758 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010013759 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Kailang Yangf6a92242007-12-13 16:52:54 +010013760
Takashi Iwai100d5eb2009-08-10 11:55:51 +020013761 spec->vmaster_nid = 0x02;
13762
Kailang Yangf6a92242007-12-13 16:52:54 +010013763 codec->patch_ops = alc_patch_ops;
13764 if (board_config == ALC269_AUTO)
13765 spec->init_hook = alc269_auto_init;
13766#ifdef CONFIG_SND_HDA_POWER_SAVE
13767 if (!spec->loopback.amplist)
13768 spec->loopback.amplist = alc269_loopbacks;
13769#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010013770 codec->proc_widget_hook = print_realtek_coef;
Kailang Yangf6a92242007-12-13 16:52:54 +010013771
13772 return 0;
13773}
13774
13775/*
Kailang Yangdf694da2005-12-05 19:42:22 +010013776 * ALC861 channel source setting (2/6 channel selection for 3-stack)
13777 */
13778
13779/*
13780 * set the path ways for 2 channel output
13781 * need to set the codec line out and mic 1 pin widgets to inputs
13782 */
13783static struct hda_verb alc861_threestack_ch2_init[] = {
13784 /* set pin widget 1Ah (line in) for input */
13785 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013786 /* set pin widget 18h (mic1/2) for input, for mic also enable
13787 * the vref
13788 */
Kailang Yangdf694da2005-12-05 19:42:22 +010013789 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13790
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013791 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
13792#if 0
13793 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
13794 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
13795#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010013796 { } /* end */
13797};
13798/*
13799 * 6ch mode
13800 * need to set the codec line out and mic 1 pin widgets to outputs
13801 */
13802static struct hda_verb alc861_threestack_ch6_init[] = {
13803 /* set pin widget 1Ah (line in) for output (Back Surround)*/
13804 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13805 /* set pin widget 18h (mic1) for output (CLFE)*/
13806 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13807
13808 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013809 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013810
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013811 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
13812#if 0
13813 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
13814 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
13815#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010013816 { } /* end */
13817};
13818
13819static struct hda_channel_mode alc861_threestack_modes[2] = {
13820 { 2, alc861_threestack_ch2_init },
13821 { 6, alc861_threestack_ch6_init },
13822};
Takashi Iwai22309c32006-08-09 16:57:28 +020013823/* Set mic1 as input and unmute the mixer */
13824static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
13825 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13826 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
13827 { } /* end */
13828};
13829/* Set mic1 as output and mute mixer */
13830static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
13831 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13832 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
13833 { } /* end */
13834};
13835
13836static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
13837 { 2, alc861_uniwill_m31_ch2_init },
13838 { 4, alc861_uniwill_m31_ch4_init },
13839};
Kailang Yangdf694da2005-12-05 19:42:22 +010013840
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013841/* Set mic1 and line-in as input and unmute the mixer */
13842static struct hda_verb alc861_asus_ch2_init[] = {
13843 /* set pin widget 1Ah (line in) for input */
13844 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013845 /* set pin widget 18h (mic1/2) for input, for mic also enable
13846 * the vref
13847 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013848 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13849
13850 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
13851#if 0
13852 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
13853 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
13854#endif
13855 { } /* end */
13856};
13857/* Set mic1 nad line-in as output and mute mixer */
13858static struct hda_verb alc861_asus_ch6_init[] = {
13859 /* set pin widget 1Ah (line in) for output (Back Surround)*/
13860 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13861 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
13862 /* set pin widget 18h (mic1) for output (CLFE)*/
13863 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13864 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
13865 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
13866 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
13867
13868 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
13869#if 0
13870 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
13871 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
13872#endif
13873 { } /* end */
13874};
13875
13876static struct hda_channel_mode alc861_asus_modes[2] = {
13877 { 2, alc861_asus_ch2_init },
13878 { 6, alc861_asus_ch6_init },
13879};
13880
Kailang Yangdf694da2005-12-05 19:42:22 +010013881/* patch-ALC861 */
13882
13883static struct snd_kcontrol_new alc861_base_mixer[] = {
13884 /* output mixer control */
13885 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13886 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
13887 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
13888 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
13889 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
13890
13891 /*Input mixer control */
13892 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
13893 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
13894 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13895 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
13896 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
13897 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
13898 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13899 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
13900 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
13901 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013902
Kailang Yangdf694da2005-12-05 19:42:22 +010013903 { } /* end */
13904};
13905
13906static struct snd_kcontrol_new alc861_3ST_mixer[] = {
13907 /* output mixer control */
13908 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13909 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
13910 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
13911 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
13912 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
13913
13914 /* Input mixer control */
13915 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
13916 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
13917 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13918 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
13919 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
13920 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
13921 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13922 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
13923 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
13924 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013925
Kailang Yangdf694da2005-12-05 19:42:22 +010013926 {
13927 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13928 .name = "Channel Mode",
13929 .info = alc_ch_mode_info,
13930 .get = alc_ch_mode_get,
13931 .put = alc_ch_mode_put,
13932 .private_value = ARRAY_SIZE(alc861_threestack_modes),
13933 },
13934 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013935};
13936
Takashi Iwaid1d985f2006-11-23 19:27:12 +010013937static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013938 /* output mixer control */
13939 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13940 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13941 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020013942
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013943 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013944};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013945
Takashi Iwai22309c32006-08-09 16:57:28 +020013946static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
13947 /* output mixer control */
13948 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13949 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
13950 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
13951 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
13952 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
13953
13954 /* Input mixer control */
13955 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
13956 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
13957 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13958 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
13959 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
13960 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
13961 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13962 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
13963 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
13964 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013965
Takashi Iwai22309c32006-08-09 16:57:28 +020013966 {
13967 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13968 .name = "Channel Mode",
13969 .info = alc_ch_mode_info,
13970 .get = alc_ch_mode_get,
13971 .put = alc_ch_mode_put,
13972 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
13973 },
13974 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013975};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013976
13977static struct snd_kcontrol_new alc861_asus_mixer[] = {
13978 /* output mixer control */
13979 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13980 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
13981 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
13982 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
13983 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
13984
13985 /* Input mixer control */
13986 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
13987 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
13988 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13989 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
13990 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
13991 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
13992 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13993 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
13994 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013995 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
13996
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013997 {
13998 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13999 .name = "Channel Mode",
14000 .info = alc_ch_mode_info,
14001 .get = alc_ch_mode_get,
14002 .put = alc_ch_mode_put,
14003 .private_value = ARRAY_SIZE(alc861_asus_modes),
14004 },
14005 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014006};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014007
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014008/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010014009static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014010 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14011 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014012 { }
14013};
14014
Kailang Yangdf694da2005-12-05 19:42:22 +010014015/*
14016 * generic initialization of ADC, input mixers and output mixers
14017 */
14018static struct hda_verb alc861_base_init_verbs[] = {
14019 /*
14020 * Unmute ADC0 and set the default input to mic-in
14021 */
14022 /* port-A for surround (rear panel) */
14023 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14024 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
14025 /* port-B for mic-in (rear panel) with vref */
14026 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14027 /* port-C for line-in (rear panel) */
14028 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14029 /* port-D for Front */
14030 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14031 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
14032 /* port-E for HP out (front panel) */
14033 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
14034 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010014035 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010014036 /* port-F for mic-in (front panel) with vref */
14037 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14038 /* port-G for CLFE (rear panel) */
14039 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14040 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
14041 /* port-H for side (rear panel) */
14042 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14043 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
14044 /* CD-in */
14045 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14046 /* route front mic to ADC1*/
14047 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
14048 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014049
Kailang Yangdf694da2005-12-05 19:42:22 +010014050 /* Unmute DAC0~3 & spdif out*/
14051 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14052 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14053 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14054 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14055 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020014056
Kailang Yangdf694da2005-12-05 19:42:22 +010014057 /* Unmute Mixer 14 (mic) 1c (Line in)*/
14058 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14059 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14060 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14061 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014062
Kailang Yangdf694da2005-12-05 19:42:22 +010014063 /* Unmute Stereo Mixer 15 */
14064 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14065 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14066 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014067 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010014068
14069 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14070 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14071 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14072 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14073 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14074 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14075 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14076 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014077 /* hp used DAC 3 (Front) */
14078 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010014079 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
14080
14081 { }
14082};
14083
14084static struct hda_verb alc861_threestack_init_verbs[] = {
14085 /*
14086 * Unmute ADC0 and set the default input to mic-in
14087 */
14088 /* port-A for surround (rear panel) */
14089 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14090 /* port-B for mic-in (rear panel) with vref */
14091 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14092 /* port-C for line-in (rear panel) */
14093 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14094 /* port-D for Front */
14095 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14096 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
14097 /* port-E for HP out (front panel) */
14098 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
14099 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010014100 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010014101 /* port-F for mic-in (front panel) with vref */
14102 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14103 /* port-G for CLFE (rear panel) */
14104 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14105 /* port-H for side (rear panel) */
14106 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14107 /* CD-in */
14108 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14109 /* route front mic to ADC1*/
14110 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
14111 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14112 /* Unmute DAC0~3 & spdif out*/
14113 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14114 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14115 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14116 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14117 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020014118
Kailang Yangdf694da2005-12-05 19:42:22 +010014119 /* Unmute Mixer 14 (mic) 1c (Line in)*/
14120 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14121 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14122 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14123 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014124
Kailang Yangdf694da2005-12-05 19:42:22 +010014125 /* Unmute Stereo Mixer 15 */
14126 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14127 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14128 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014129 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010014130
14131 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14132 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14133 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14134 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14135 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14136 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14137 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14138 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014139 /* hp used DAC 3 (Front) */
14140 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010014141 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
14142 { }
14143};
Takashi Iwai22309c32006-08-09 16:57:28 +020014144
14145static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
14146 /*
14147 * Unmute ADC0 and set the default input to mic-in
14148 */
14149 /* port-A for surround (rear panel) */
14150 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14151 /* port-B for mic-in (rear panel) with vref */
14152 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14153 /* port-C for line-in (rear panel) */
14154 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14155 /* port-D for Front */
14156 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14157 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
14158 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014159 /* this has to be set to VREF80 */
14160 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020014161 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010014162 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020014163 /* port-F for mic-in (front panel) with vref */
14164 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14165 /* port-G for CLFE (rear panel) */
14166 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14167 /* port-H for side (rear panel) */
14168 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14169 /* CD-in */
14170 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14171 /* route front mic to ADC1*/
14172 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
14173 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14174 /* Unmute DAC0~3 & spdif out*/
14175 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14176 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14177 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14178 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14179 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020014180
Takashi Iwai22309c32006-08-09 16:57:28 +020014181 /* Unmute Mixer 14 (mic) 1c (Line in)*/
14182 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14183 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14184 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14185 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014186
Takashi Iwai22309c32006-08-09 16:57:28 +020014187 /* Unmute Stereo Mixer 15 */
14188 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14189 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14190 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014191 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020014192
14193 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14194 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14195 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14196 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14197 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14198 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14199 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14200 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014201 /* hp used DAC 3 (Front) */
14202 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020014203 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
14204 { }
14205};
14206
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014207static struct hda_verb alc861_asus_init_verbs[] = {
14208 /*
14209 * Unmute ADC0 and set the default input to mic-in
14210 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014211 /* port-A for surround (rear panel)
14212 * according to codec#0 this is the HP jack
14213 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014214 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
14215 /* route front PCM to HP */
14216 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
14217 /* port-B for mic-in (rear panel) with vref */
14218 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14219 /* port-C for line-in (rear panel) */
14220 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14221 /* port-D for Front */
14222 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14223 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
14224 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014225 /* this has to be set to VREF80 */
14226 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014227 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010014228 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014229 /* port-F for mic-in (front panel) with vref */
14230 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14231 /* port-G for CLFE (rear panel) */
14232 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14233 /* port-H for side (rear panel) */
14234 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14235 /* CD-in */
14236 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14237 /* route front mic to ADC1*/
14238 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
14239 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14240 /* Unmute DAC0~3 & spdif out*/
14241 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14242 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14243 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14244 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14245 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14246 /* Unmute Mixer 14 (mic) 1c (Line in)*/
14247 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14248 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14249 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14250 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014251
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014252 /* Unmute Stereo Mixer 15 */
14253 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14254 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14255 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014256 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014257
14258 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14259 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14260 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14261 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14262 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14263 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14264 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14265 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014266 /* hp used DAC 3 (Front) */
14267 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014268 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
14269 { }
14270};
14271
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014272/* additional init verbs for ASUS laptops */
14273static struct hda_verb alc861_asus_laptop_init_verbs[] = {
14274 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
14275 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
14276 { }
14277};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014278
Kailang Yangdf694da2005-12-05 19:42:22 +010014279/*
14280 * generic initialization of ADC, input mixers and output mixers
14281 */
14282static struct hda_verb alc861_auto_init_verbs[] = {
14283 /*
14284 * Unmute ADC0 and set the default input to mic-in
14285 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014286 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010014287 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014288
Kailang Yangdf694da2005-12-05 19:42:22 +010014289 /* Unmute DAC0~3 & spdif out*/
14290 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14291 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14292 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14293 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14294 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020014295
Kailang Yangdf694da2005-12-05 19:42:22 +010014296 /* Unmute Mixer 14 (mic) 1c (Line in)*/
14297 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14298 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14299 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14300 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014301
Kailang Yangdf694da2005-12-05 19:42:22 +010014302 /* Unmute Stereo Mixer 15 */
14303 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14304 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14305 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
14306 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
14307
Takashi Iwai1c209302009-07-22 15:17:45 +020014308 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14309 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14310 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14311 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14312 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14313 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14314 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14315 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangdf694da2005-12-05 19:42:22 +010014316
14317 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14318 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020014319 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
14320 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010014321 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14322 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020014323 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
14324 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010014325
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014326 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010014327
14328 { }
14329};
14330
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014331static struct hda_verb alc861_toshiba_init_verbs[] = {
14332 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014333
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014334 { }
14335};
14336
14337/* toggle speaker-output according to the hp-jack state */
14338static void alc861_toshiba_automute(struct hda_codec *codec)
14339{
Wu Fengguang864f92b2009-11-18 12:38:02 +080014340 unsigned int present = snd_hda_jack_detect(codec, 0x0f);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014341
Takashi Iwai47fd8302007-08-10 17:11:07 +020014342 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
14343 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
14344 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
14345 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014346}
14347
14348static void alc861_toshiba_unsol_event(struct hda_codec *codec,
14349 unsigned int res)
14350{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014351 if ((res >> 26) == ALC880_HP_EVENT)
14352 alc861_toshiba_automute(codec);
14353}
14354
Sasha Alexandrdef319f2009-06-16 16:00:15 -040014355/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010014356#define alc861_pcm_analog_playback alc880_pcm_analog_playback
14357#define alc861_pcm_analog_capture alc880_pcm_analog_capture
14358#define alc861_pcm_digital_playback alc880_pcm_digital_playback
14359#define alc861_pcm_digital_capture alc880_pcm_digital_capture
14360
14361
14362#define ALC861_DIGOUT_NID 0x07
14363
14364static struct hda_channel_mode alc861_8ch_modes[1] = {
14365 { 8, NULL }
14366};
14367
14368static hda_nid_t alc861_dac_nids[4] = {
14369 /* front, surround, clfe, side */
14370 0x03, 0x06, 0x05, 0x04
14371};
14372
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014373static hda_nid_t alc660_dac_nids[3] = {
14374 /* front, clfe, surround */
14375 0x03, 0x05, 0x06
14376};
14377
Kailang Yangdf694da2005-12-05 19:42:22 +010014378static hda_nid_t alc861_adc_nids[1] = {
14379 /* ADC0-2 */
14380 0x08,
14381};
14382
14383static struct hda_input_mux alc861_capture_source = {
14384 .num_items = 5,
14385 .items = {
14386 { "Mic", 0x0 },
14387 { "Front Mic", 0x3 },
14388 { "Line", 0x1 },
14389 { "CD", 0x4 },
14390 { "Mixer", 0x5 },
14391 },
14392};
14393
Takashi Iwai1c209302009-07-22 15:17:45 +020014394static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
14395{
14396 struct alc_spec *spec = codec->spec;
14397 hda_nid_t mix, srcs[5];
14398 int i, j, num;
14399
14400 if (snd_hda_get_connections(codec, pin, &mix, 1) != 1)
14401 return 0;
14402 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
14403 if (num < 0)
14404 return 0;
14405 for (i = 0; i < num; i++) {
14406 unsigned int type;
Takashi Iwaia22d5432009-07-27 12:54:26 +020014407 type = get_wcaps_type(get_wcaps(codec, srcs[i]));
Takashi Iwai1c209302009-07-22 15:17:45 +020014408 if (type != AC_WID_AUD_OUT)
14409 continue;
14410 for (j = 0; j < spec->multiout.num_dacs; j++)
14411 if (spec->multiout.dac_nids[j] == srcs[i])
14412 break;
14413 if (j >= spec->multiout.num_dacs)
14414 return srcs[i];
14415 }
14416 return 0;
14417}
14418
Kailang Yangdf694da2005-12-05 19:42:22 +010014419/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwai1c209302009-07-22 15:17:45 +020014420static int alc861_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014421 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010014422{
Takashi Iwai1c209302009-07-22 15:17:45 +020014423 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010014424 int i;
Takashi Iwai1c209302009-07-22 15:17:45 +020014425 hda_nid_t nid, dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010014426
14427 spec->multiout.dac_nids = spec->private_dac_nids;
14428 for (i = 0; i < cfg->line_outs; i++) {
14429 nid = cfg->line_out_pins[i];
Takashi Iwai1c209302009-07-22 15:17:45 +020014430 dac = alc861_look_for_dac(codec, nid);
14431 if (!dac)
14432 continue;
14433 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010014434 }
Kailang Yangdf694da2005-12-05 19:42:22 +010014435 return 0;
14436}
14437
Takashi Iwai1c209302009-07-22 15:17:45 +020014438static int alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
14439 hda_nid_t nid, unsigned int chs)
Kailang Yangdf694da2005-12-05 19:42:22 +010014440{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020014441 return add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai1c209302009-07-22 15:17:45 +020014442 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
14443}
14444
14445/* add playback controls from the parsed DAC table */
14446static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
14447 const struct auto_pin_cfg *cfg)
14448{
14449 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014450 static const char *chname[4] = {
14451 "Front", "Surround", NULL /*CLFE*/, "Side"
14452 };
Kailang Yangdf694da2005-12-05 19:42:22 +010014453 hda_nid_t nid;
Takashi Iwai1c209302009-07-22 15:17:45 +020014454 int i, err;
14455
14456 if (cfg->line_outs == 1) {
14457 const char *pfx = NULL;
14458 if (!cfg->hp_outs)
14459 pfx = "Master";
14460 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
14461 pfx = "Speaker";
14462 if (pfx) {
14463 nid = spec->multiout.dac_nids[0];
14464 return alc861_create_out_sw(codec, pfx, nid, 3);
14465 }
14466 }
Kailang Yangdf694da2005-12-05 19:42:22 +010014467
14468 for (i = 0; i < cfg->line_outs; i++) {
14469 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014470 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010014471 continue;
Takashi Iwai1c209302009-07-22 15:17:45 +020014472 if (i == 2) {
Kailang Yangdf694da2005-12-05 19:42:22 +010014473 /* Center/LFE */
Takashi Iwai1c209302009-07-22 15:17:45 +020014474 err = alc861_create_out_sw(codec, "Center", nid, 1);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014475 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010014476 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020014477 err = alc861_create_out_sw(codec, "LFE", nid, 2);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014478 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010014479 return err;
14480 } else {
Takashi Iwai1c209302009-07-22 15:17:45 +020014481 err = alc861_create_out_sw(codec, chname[i], nid, 3);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014482 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010014483 return err;
14484 }
14485 }
14486 return 0;
14487}
14488
Takashi Iwai1c209302009-07-22 15:17:45 +020014489static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010014490{
Takashi Iwai1c209302009-07-22 15:17:45 +020014491 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010014492 int err;
14493 hda_nid_t nid;
14494
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014495 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010014496 return 0;
14497
14498 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
Takashi Iwai1c209302009-07-22 15:17:45 +020014499 nid = alc861_look_for_dac(codec, pin);
14500 if (nid) {
14501 err = alc861_create_out_sw(codec, "Headphone", nid, 3);
14502 if (err < 0)
14503 return err;
14504 spec->multiout.hp_nid = nid;
14505 }
Kailang Yangdf694da2005-12-05 19:42:22 +010014506 }
14507 return 0;
14508}
14509
14510/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020014511static int alc861_auto_create_input_ctls(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014512 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010014513{
Takashi Iwai05f5f472009-08-25 13:10:18 +020014514 return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x08, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010014515}
14516
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014517static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
14518 hda_nid_t nid,
Takashi Iwai1c209302009-07-22 15:17:45 +020014519 int pin_type, hda_nid_t dac)
Kailang Yangdf694da2005-12-05 19:42:22 +010014520{
Takashi Iwai1c209302009-07-22 15:17:45 +020014521 hda_nid_t mix, srcs[5];
14522 int i, num;
14523
Jacek Luczak564c5be2008-05-03 18:41:23 +020014524 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
14525 pin_type);
Takashi Iwai1c209302009-07-22 15:17:45 +020014526 snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Jacek Luczak564c5be2008-05-03 18:41:23 +020014527 AMP_OUT_UNMUTE);
Takashi Iwai1c209302009-07-22 15:17:45 +020014528 if (snd_hda_get_connections(codec, nid, &mix, 1) != 1)
14529 return;
14530 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
14531 if (num < 0)
14532 return;
14533 for (i = 0; i < num; i++) {
14534 unsigned int mute;
14535 if (srcs[i] == dac || srcs[i] == 0x15)
14536 mute = AMP_IN_UNMUTE(i);
14537 else
14538 mute = AMP_IN_MUTE(i);
14539 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
14540 mute);
14541 }
Kailang Yangdf694da2005-12-05 19:42:22 +010014542}
14543
14544static void alc861_auto_init_multi_out(struct hda_codec *codec)
14545{
14546 struct alc_spec *spec = codec->spec;
14547 int i;
14548
14549 for (i = 0; i < spec->autocfg.line_outs; i++) {
14550 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020014551 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010014552 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020014553 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014554 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010014555 }
14556}
14557
14558static void alc861_auto_init_hp_out(struct hda_codec *codec)
14559{
14560 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010014561
Takashi Iwai15870f02009-10-05 08:25:13 +020014562 if (spec->autocfg.hp_outs)
14563 alc861_auto_set_output_and_unmute(codec,
14564 spec->autocfg.hp_pins[0],
14565 PIN_HP,
Takashi Iwai1c209302009-07-22 15:17:45 +020014566 spec->multiout.hp_nid);
Takashi Iwai15870f02009-10-05 08:25:13 +020014567 if (spec->autocfg.speaker_outs)
14568 alc861_auto_set_output_and_unmute(codec,
14569 spec->autocfg.speaker_pins[0],
14570 PIN_OUT,
Takashi Iwai1c209302009-07-22 15:17:45 +020014571 spec->multiout.dac_nids[0]);
Kailang Yangdf694da2005-12-05 19:42:22 +010014572}
14573
14574static void alc861_auto_init_analog_input(struct hda_codec *codec)
14575{
14576 struct alc_spec *spec = codec->spec;
14577 int i;
14578
14579 for (i = 0; i < AUTO_PIN_LAST; i++) {
14580 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai23f0c042009-02-26 13:03:58 +010014581 if (nid >= 0x0c && nid <= 0x11)
14582 alc_set_input_pin(codec, nid, i);
Kailang Yangdf694da2005-12-05 19:42:22 +010014583 }
14584}
14585
14586/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014587/* return 1 if successful, 0 if the proper config is not found,
14588 * or a negative error code
14589 */
Kailang Yangdf694da2005-12-05 19:42:22 +010014590static int alc861_parse_auto_config(struct hda_codec *codec)
14591{
14592 struct alc_spec *spec = codec->spec;
14593 int err;
14594 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
14595
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014596 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
14597 alc861_ignore);
14598 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010014599 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014600 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010014601 return 0; /* can't find valid BIOS pin config */
14602
Takashi Iwai1c209302009-07-22 15:17:45 +020014603 err = alc861_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014604 if (err < 0)
14605 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020014606 err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014607 if (err < 0)
14608 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020014609 err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014610 if (err < 0)
14611 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020014612 err = alc861_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014613 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010014614 return err;
14615
14616 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
14617
Takashi Iwai0852d7a2009-02-11 11:35:15 +010014618 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010014619 spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
14620
Takashi Iwai603c4012008-07-30 15:01:44 +020014621 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010014622 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010014623
Takashi Iwaid88897e2008-10-31 15:01:37 +010014624 add_verb(spec, alc861_auto_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +010014625
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020014626 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020014627 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010014628
14629 spec->adc_nids = alc861_adc_nids;
14630 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
Takashi Iwaib59bdf32009-08-11 09:47:30 +020014631 set_capture_mixer(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010014632
Takashi Iwai4a79ba32009-04-22 16:31:35 +020014633 alc_ssid_check(codec, 0x0e, 0x0f, 0x0b);
14634
Kailang Yangdf694da2005-12-05 19:42:22 +010014635 return 1;
14636}
14637
Takashi Iwaiae6b8132006-03-03 16:47:17 +010014638/* additional initialization for auto-configuration model */
14639static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010014640{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014641 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010014642 alc861_auto_init_multi_out(codec);
14643 alc861_auto_init_hp_out(codec);
14644 alc861_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014645 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020014646 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010014647}
14648
Takashi Iwaicb53c622007-08-10 17:21:45 +020014649#ifdef CONFIG_SND_HDA_POWER_SAVE
14650static struct hda_amp_list alc861_loopbacks[] = {
14651 { 0x15, HDA_INPUT, 0 },
14652 { 0x15, HDA_INPUT, 1 },
14653 { 0x15, HDA_INPUT, 2 },
14654 { 0x15, HDA_INPUT, 3 },
14655 { } /* end */
14656};
14657#endif
14658
Kailang Yangdf694da2005-12-05 19:42:22 +010014659
14660/*
14661 * configuration and preset
14662 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010014663static const char *alc861_models[ALC861_MODEL_LAST] = {
14664 [ALC861_3ST] = "3stack",
14665 [ALC660_3ST] = "3stack-660",
14666 [ALC861_3ST_DIG] = "3stack-dig",
14667 [ALC861_6ST_DIG] = "6stack-dig",
14668 [ALC861_UNIWILL_M31] = "uniwill-m31",
14669 [ALC861_TOSHIBA] = "toshiba",
14670 [ALC861_ASUS] = "asus",
14671 [ALC861_ASUS_LAPTOP] = "asus-laptop",
14672 [ALC861_AUTO] = "auto",
14673};
14674
14675static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010014676 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010014677 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
14678 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
14679 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010014680 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020014681 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010014682 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020014683 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
14684 * Any other models that need this preset?
14685 */
14686 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020014687 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
14688 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010014689 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
14690 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
14691 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
14692 /* FIXME: the below seems conflict */
14693 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
14694 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
14695 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010014696 {}
14697};
14698
14699static struct alc_config_preset alc861_presets[] = {
14700 [ALC861_3ST] = {
14701 .mixers = { alc861_3ST_mixer },
14702 .init_verbs = { alc861_threestack_init_verbs },
14703 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14704 .dac_nids = alc861_dac_nids,
14705 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
14706 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020014707 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010014708 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14709 .adc_nids = alc861_adc_nids,
14710 .input_mux = &alc861_capture_source,
14711 },
14712 [ALC861_3ST_DIG] = {
14713 .mixers = { alc861_base_mixer },
14714 .init_verbs = { alc861_threestack_init_verbs },
14715 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14716 .dac_nids = alc861_dac_nids,
14717 .dig_out_nid = ALC861_DIGOUT_NID,
14718 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
14719 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020014720 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010014721 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14722 .adc_nids = alc861_adc_nids,
14723 .input_mux = &alc861_capture_source,
14724 },
14725 [ALC861_6ST_DIG] = {
14726 .mixers = { alc861_base_mixer },
14727 .init_verbs = { alc861_base_init_verbs },
14728 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14729 .dac_nids = alc861_dac_nids,
14730 .dig_out_nid = ALC861_DIGOUT_NID,
14731 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
14732 .channel_mode = alc861_8ch_modes,
14733 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14734 .adc_nids = alc861_adc_nids,
14735 .input_mux = &alc861_capture_source,
14736 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014737 [ALC660_3ST] = {
14738 .mixers = { alc861_3ST_mixer },
14739 .init_verbs = { alc861_threestack_init_verbs },
14740 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
14741 .dac_nids = alc660_dac_nids,
14742 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
14743 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020014744 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014745 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14746 .adc_nids = alc861_adc_nids,
14747 .input_mux = &alc861_capture_source,
14748 },
Takashi Iwai22309c32006-08-09 16:57:28 +020014749 [ALC861_UNIWILL_M31] = {
14750 .mixers = { alc861_uniwill_m31_mixer },
14751 .init_verbs = { alc861_uniwill_m31_init_verbs },
14752 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14753 .dac_nids = alc861_dac_nids,
14754 .dig_out_nid = ALC861_DIGOUT_NID,
14755 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
14756 .channel_mode = alc861_uniwill_m31_modes,
14757 .need_dac_fix = 1,
14758 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14759 .adc_nids = alc861_adc_nids,
14760 .input_mux = &alc861_capture_source,
14761 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014762 [ALC861_TOSHIBA] = {
14763 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014764 .init_verbs = { alc861_base_init_verbs,
14765 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014766 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14767 .dac_nids = alc861_dac_nids,
14768 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
14769 .channel_mode = alc883_3ST_2ch_modes,
14770 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14771 .adc_nids = alc861_adc_nids,
14772 .input_mux = &alc861_capture_source,
14773 .unsol_event = alc861_toshiba_unsol_event,
14774 .init_hook = alc861_toshiba_automute,
14775 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014776 [ALC861_ASUS] = {
14777 .mixers = { alc861_asus_mixer },
14778 .init_verbs = { alc861_asus_init_verbs },
14779 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14780 .dac_nids = alc861_dac_nids,
14781 .dig_out_nid = ALC861_DIGOUT_NID,
14782 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
14783 .channel_mode = alc861_asus_modes,
14784 .need_dac_fix = 1,
14785 .hp_nid = 0x06,
14786 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14787 .adc_nids = alc861_adc_nids,
14788 .input_mux = &alc861_capture_source,
14789 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014790 [ALC861_ASUS_LAPTOP] = {
14791 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
14792 .init_verbs = { alc861_asus_init_verbs,
14793 alc861_asus_laptop_init_verbs },
14794 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14795 .dac_nids = alc861_dac_nids,
14796 .dig_out_nid = ALC861_DIGOUT_NID,
14797 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
14798 .channel_mode = alc883_3ST_2ch_modes,
14799 .need_dac_fix = 1,
14800 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14801 .adc_nids = alc861_adc_nids,
14802 .input_mux = &alc861_capture_source,
14803 },
14804};
Kailang Yangdf694da2005-12-05 19:42:22 +010014805
Takashi Iwaicfc9b062009-12-01 12:19:37 +010014806/* Pin config fixes */
14807enum {
14808 PINFIX_FSC_AMILO_PI1505,
14809};
14810
14811static struct alc_pincfg alc861_fsc_amilo_pi1505_pinfix[] = {
14812 { 0x0b, 0x0221101f }, /* HP */
14813 { 0x0f, 0x90170310 }, /* speaker */
14814 { }
14815};
14816
14817static const struct alc_fixup alc861_fixups[] = {
14818 [PINFIX_FSC_AMILO_PI1505] = {
14819 .pins = alc861_fsc_amilo_pi1505_pinfix
14820 },
14821};
14822
14823static struct snd_pci_quirk alc861_fixup_tbl[] = {
14824 SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
14825 {}
14826};
Kailang Yangdf694da2005-12-05 19:42:22 +010014827
14828static int patch_alc861(struct hda_codec *codec)
14829{
14830 struct alc_spec *spec;
14831 int board_config;
14832 int err;
14833
Robert P. J. Daydc041e02006-12-19 14:44:15 +010014834 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010014835 if (spec == NULL)
14836 return -ENOMEM;
14837
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014838 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010014839
Takashi Iwaif5fcc132006-11-24 17:07:44 +010014840 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
14841 alc861_models,
14842 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014843
Takashi Iwaif5fcc132006-11-24 17:07:44 +010014844 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020014845 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
14846 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010014847 board_config = ALC861_AUTO;
14848 }
14849
Takashi Iwaicfc9b062009-12-01 12:19:37 +010014850 alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups);
14851
Kailang Yangdf694da2005-12-05 19:42:22 +010014852 if (board_config == ALC861_AUTO) {
14853 /* automatic parse from the BIOS config */
14854 err = alc861_parse_auto_config(codec);
14855 if (err < 0) {
14856 alc_free(codec);
14857 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014858 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014859 printk(KERN_INFO
14860 "hda_codec: Cannot set up configuration "
14861 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010014862 board_config = ALC861_3ST_DIG;
14863 }
14864 }
14865
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090014866 err = snd_hda_attach_beep_device(codec, 0x23);
14867 if (err < 0) {
14868 alc_free(codec);
14869 return err;
14870 }
14871
Kailang Yangdf694da2005-12-05 19:42:22 +010014872 if (board_config != ALC861_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020014873 setup_preset(codec, &alc861_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010014874
Kailang Yangdf694da2005-12-05 19:42:22 +010014875 spec->stream_analog_playback = &alc861_pcm_analog_playback;
14876 spec->stream_analog_capture = &alc861_pcm_analog_capture;
14877
Kailang Yangdf694da2005-12-05 19:42:22 +010014878 spec->stream_digital_playback = &alc861_pcm_digital_playback;
14879 spec->stream_digital_capture = &alc861_pcm_digital_capture;
14880
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010014881 set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
14882
Takashi Iwai2134ea42008-01-10 16:53:55 +010014883 spec->vmaster_nid = 0x03;
14884
Kailang Yangdf694da2005-12-05 19:42:22 +010014885 codec->patch_ops = alc_patch_ops;
14886 if (board_config == ALC861_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010014887 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020014888#ifdef CONFIG_SND_HDA_POWER_SAVE
14889 if (!spec->loopback.amplist)
14890 spec->loopback.amplist = alc861_loopbacks;
14891#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010014892 codec->proc_widget_hook = print_realtek_coef;
Kailang Yangea1fb292008-08-26 12:58:38 +020014893
Kailang Yangdf694da2005-12-05 19:42:22 +010014894 return 0;
14895}
14896
14897/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014898 * ALC861-VD support
14899 *
14900 * Based on ALC882
14901 *
14902 * In addition, an independent DAC
14903 */
14904#define ALC861VD_DIGOUT_NID 0x06
14905
14906static hda_nid_t alc861vd_dac_nids[4] = {
14907 /* front, surr, clfe, side surr */
14908 0x02, 0x03, 0x04, 0x05
14909};
14910
14911/* dac_nids for ALC660vd are in a different order - according to
14912 * Realtek's driver.
Sasha Alexandrdef319f2009-06-16 16:00:15 -040014913 * This should probably result in a different mixer for 6stack models
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014914 * of ALC660vd codecs, but for now there is only 3stack mixer
14915 * - and it is the same as in 861vd.
14916 * adc_nids in ALC660vd are (is) the same as in 861vd
14917 */
14918static hda_nid_t alc660vd_dac_nids[3] = {
14919 /* front, rear, clfe, rear_surr */
14920 0x02, 0x04, 0x03
14921};
14922
14923static hda_nid_t alc861vd_adc_nids[1] = {
14924 /* ADC0 */
14925 0x09,
14926};
14927
Takashi Iwaie1406342008-02-11 18:32:32 +010014928static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
14929
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014930/* input MUX */
14931/* FIXME: should be a matrix-type input source selection */
14932static struct hda_input_mux alc861vd_capture_source = {
14933 .num_items = 4,
14934 .items = {
14935 { "Mic", 0x0 },
14936 { "Front Mic", 0x1 },
14937 { "Line", 0x2 },
14938 { "CD", 0x4 },
14939 },
14940};
14941
Kailang Yang272a5272007-05-14 11:00:38 +020014942static struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010014943 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020014944 .items = {
Tobin Davisb419f342008-03-07 11:57:51 +010014945 { "Ext Mic", 0x0 },
14946 { "Int Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020014947 },
14948};
14949
Kailang Yangd1a991a2007-08-15 16:21:59 +020014950static struct hda_input_mux alc861vd_hp_capture_source = {
14951 .num_items = 2,
14952 .items = {
14953 { "Front Mic", 0x0 },
14954 { "ATAPI Mic", 0x1 },
14955 },
14956};
14957
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014958/*
14959 * 2ch mode
14960 */
14961static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
14962 { 2, NULL }
14963};
14964
14965/*
14966 * 6ch mode
14967 */
14968static struct hda_verb alc861vd_6stack_ch6_init[] = {
14969 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14970 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14971 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14972 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14973 { } /* end */
14974};
14975
14976/*
14977 * 8ch mode
14978 */
14979static struct hda_verb alc861vd_6stack_ch8_init[] = {
14980 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14981 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14982 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14983 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14984 { } /* end */
14985};
14986
14987static struct hda_channel_mode alc861vd_6stack_modes[2] = {
14988 { 6, alc861vd_6stack_ch6_init },
14989 { 8, alc861vd_6stack_ch8_init },
14990};
14991
14992static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
14993 {
14994 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14995 .name = "Channel Mode",
14996 .info = alc_ch_mode_info,
14997 .get = alc_ch_mode_get,
14998 .put = alc_ch_mode_put,
14999 },
15000 { } /* end */
15001};
15002
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015003/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
15004 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
15005 */
15006static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
15007 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15008 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
15009
15010 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15011 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
15012
15013 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
15014 HDA_OUTPUT),
15015 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
15016 HDA_OUTPUT),
15017 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
15018 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
15019
15020 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
15021 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
15022
15023 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15024
15025 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
15026 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15027 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15028
15029 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
15030 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15031 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15032
15033 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15034 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15035
15036 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
15037 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
15038
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015039 { } /* end */
15040};
15041
15042static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
15043 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15044 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
15045
15046 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15047
15048 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
15049 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15050 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15051
15052 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
15053 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15054 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15055
15056 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15057 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15058
15059 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
15060 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
15061
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015062 { } /* end */
15063};
15064
Kailang Yangbdd148a2007-05-08 15:19:08 +020015065static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
15066 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15067 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
15068 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
15069
15070 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15071
15072 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
15073 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15074 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15075
15076 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
15077 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15078 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15079
15080 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
15081 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
15082
15083 { } /* end */
15084};
15085
Tobin Davisb419f342008-03-07 11:57:51 +010015086/* Pin assignment: Speaker=0x14, HP = 0x15,
15087 * Ext Mic=0x18, Int Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020015088 */
15089static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010015090 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15091 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020015092 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15093 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisb419f342008-03-07 11:57:51 +010015094 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
15095 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15096 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15097 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
15098 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15099 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020015100 { } /* end */
15101};
15102
Kailang Yangd1a991a2007-08-15 16:21:59 +020015103/* Pin assignment: Speaker=0x14, Line-out = 0x15,
15104 * Front Mic=0x18, ATAPI Mic = 0x19,
15105 */
15106static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
15107 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15108 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
15109 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15110 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
15111 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15112 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15113 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15114 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020015115
Kailang Yangd1a991a2007-08-15 16:21:59 +020015116 { } /* end */
15117};
15118
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015119/*
15120 * generic initialization of ADC, input mixers and output mixers
15121 */
15122static struct hda_verb alc861vd_volume_init_verbs[] = {
15123 /*
15124 * Unmute ADC0 and set the default input to mic-in
15125 */
15126 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
15127 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15128
15129 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
15130 * the analog-loopback mixer widget
15131 */
15132 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020015133 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15134 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15135 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15136 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
15137 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015138
15139 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020015140 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15141 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15142 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015143 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015144
15145 /*
15146 * Set up output mixers (0x02 - 0x05)
15147 */
15148 /* set vol=0 to output mixers */
15149 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15150 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15151 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15152 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15153
15154 /* set up input amps for analog loopback */
15155 /* Amp Indices: DAC = 0, mixer = 1 */
15156 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15157 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15158 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15159 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15160 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15161 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15162 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15163 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15164
15165 { }
15166};
15167
15168/*
15169 * 3-stack pin configuration:
15170 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
15171 */
15172static struct hda_verb alc861vd_3stack_init_verbs[] = {
15173 /*
15174 * Set pin mode and muting
15175 */
15176 /* set front pin widgets 0x14 for output */
15177 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15178 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15179 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
15180
15181 /* Mic (rear) pin: input vref at 80% */
15182 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
15183 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15184 /* Front Mic pin: input vref at 80% */
15185 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
15186 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15187 /* Line In pin: input */
15188 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15189 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15190 /* Line-2 In: Headphone output (output 0 - 0x0c) */
15191 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15192 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15193 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
15194 /* CD pin widget for input */
15195 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15196
15197 { }
15198};
15199
15200/*
15201 * 6-stack pin configuration:
15202 */
15203static struct hda_verb alc861vd_6stack_init_verbs[] = {
15204 /*
15205 * Set pin mode and muting
15206 */
15207 /* set front pin widgets 0x14 for output */
15208 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15209 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15210 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
15211
15212 /* Rear Pin: output 1 (0x0d) */
15213 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15214 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15215 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
15216 /* CLFE Pin: output 2 (0x0e) */
15217 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15218 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15219 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
15220 /* Side Pin: output 3 (0x0f) */
15221 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15222 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15223 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
15224
15225 /* Mic (rear) pin: input vref at 80% */
15226 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
15227 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15228 /* Front Mic pin: input vref at 80% */
15229 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
15230 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15231 /* Line In pin: input */
15232 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15233 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15234 /* Line-2 In: Headphone output (output 0 - 0x0c) */
15235 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15236 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15237 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
15238 /* CD pin widget for input */
15239 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15240
15241 { }
15242};
15243
Kailang Yangbdd148a2007-05-08 15:19:08 +020015244static struct hda_verb alc861vd_eapd_verbs[] = {
15245 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
15246 { }
15247};
15248
Kailang Yangf9423e72008-05-27 12:32:25 +020015249static struct hda_verb alc660vd_eapd_verbs[] = {
15250 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
15251 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
15252 { }
15253};
15254
Kailang Yangbdd148a2007-05-08 15:19:08 +020015255static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
15256 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15257 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15258 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
15259 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020015260 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020015261 {}
15262};
15263
Kailang Yangbdd148a2007-05-08 15:19:08 +020015264static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
15265{
15266 unsigned int present;
15267 unsigned char bits;
15268
Wu Fengguang864f92b2009-11-18 12:38:02 +080015269 present = snd_hda_jack_detect(codec, 0x18);
Takashi Iwai47fd8302007-08-10 17:11:07 +020015270 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080015271
Takashi Iwai47fd8302007-08-10 17:11:07 +020015272 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
15273 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020015274}
15275
Takashi Iwai4f5d17062009-08-11 18:17:46 +020015276static void alc861vd_lenovo_setup(struct hda_codec *codec)
Kailang Yangbdd148a2007-05-08 15:19:08 +020015277{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015278 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015279 spec->autocfg.hp_pins[0] = 0x1b;
15280 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020015281}
15282
15283static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
15284{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015285 alc_automute_amp(codec);
Kailang Yangbdd148a2007-05-08 15:19:08 +020015286 alc861vd_lenovo_mic_automute(codec);
15287}
15288
15289static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
15290 unsigned int res)
15291{
15292 switch (res >> 26) {
Kailang Yangbdd148a2007-05-08 15:19:08 +020015293 case ALC880_MIC_EVENT:
15294 alc861vd_lenovo_mic_automute(codec);
15295 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015296 default:
15297 alc_automute_amp_unsol_event(codec, res);
15298 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +020015299 }
15300}
15301
Kailang Yang272a5272007-05-14 11:00:38 +020015302static struct hda_verb alc861vd_dallas_verbs[] = {
15303 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15304 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15305 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15306 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15307
15308 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15309 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15310 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15311 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15312 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15313 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15314 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15315 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015316
Kailang Yang272a5272007-05-14 11:00:38 +020015317 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15318 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15319 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15320 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15321 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15322 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15323 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15324 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15325
15326 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
15327 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15328 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
15329 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15330 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15331 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15332 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15333 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15334
15335 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15336 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
15337 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15338 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
15339
15340 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015341 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020015342 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15343
15344 { } /* end */
15345};
15346
15347/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020015348static void alc861vd_dallas_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +020015349{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015350 struct alc_spec *spec = codec->spec;
Kailang Yang272a5272007-05-14 11:00:38 +020015351
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015352 spec->autocfg.hp_pins[0] = 0x15;
15353 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang272a5272007-05-14 11:00:38 +020015354}
15355
Takashi Iwaicb53c622007-08-10 17:21:45 +020015356#ifdef CONFIG_SND_HDA_POWER_SAVE
15357#define alc861vd_loopbacks alc880_loopbacks
15358#endif
15359
Sasha Alexandrdef319f2009-06-16 16:00:15 -040015360/* pcm configuration: identical with ALC880 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015361#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
15362#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
15363#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
15364#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
15365
15366/*
15367 * configuration and preset
15368 */
15369static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
15370 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020015371 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Takashi Iwai13c94742008-11-05 08:06:08 +010015372 [ALC660VD_ASUS_V1S] = "asus-v1s",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015373 [ALC861VD_3ST] = "3stack",
15374 [ALC861VD_3ST_DIG] = "3stack-digout",
15375 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020015376 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020015377 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020015378 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015379 [ALC861VD_AUTO] = "auto",
15380};
15381
15382static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015383 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
15384 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010015385 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020015386 /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */
Takashi Iwai13c94742008-11-05 08:06:08 +010015387 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
Mike Crash6963f842007-06-25 12:12:51 +020015388 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015389 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015390 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020015391 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Takashi Iwaice577e82009-08-03 08:23:52 +020015392 SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai542d7c62007-08-16 18:57:30 +020015393 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010015394 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020015395 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010015396 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020015397 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015398 {}
15399};
15400
15401static struct alc_config_preset alc861vd_presets[] = {
15402 [ALC660VD_3ST] = {
15403 .mixers = { alc861vd_3st_mixer },
15404 .init_verbs = { alc861vd_volume_init_verbs,
15405 alc861vd_3stack_init_verbs },
15406 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
15407 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015408 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
15409 .channel_mode = alc861vd_3stack_2ch_modes,
15410 .input_mux = &alc861vd_capture_source,
15411 },
Mike Crash6963f842007-06-25 12:12:51 +020015412 [ALC660VD_3ST_DIG] = {
15413 .mixers = { alc861vd_3st_mixer },
15414 .init_verbs = { alc861vd_volume_init_verbs,
15415 alc861vd_3stack_init_verbs },
15416 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
15417 .dac_nids = alc660vd_dac_nids,
15418 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020015419 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
15420 .channel_mode = alc861vd_3stack_2ch_modes,
15421 .input_mux = &alc861vd_capture_source,
15422 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015423 [ALC861VD_3ST] = {
15424 .mixers = { alc861vd_3st_mixer },
15425 .init_verbs = { alc861vd_volume_init_verbs,
15426 alc861vd_3stack_init_verbs },
15427 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
15428 .dac_nids = alc861vd_dac_nids,
15429 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
15430 .channel_mode = alc861vd_3stack_2ch_modes,
15431 .input_mux = &alc861vd_capture_source,
15432 },
15433 [ALC861VD_3ST_DIG] = {
15434 .mixers = { alc861vd_3st_mixer },
15435 .init_verbs = { alc861vd_volume_init_verbs,
15436 alc861vd_3stack_init_verbs },
15437 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
15438 .dac_nids = alc861vd_dac_nids,
15439 .dig_out_nid = ALC861VD_DIGOUT_NID,
15440 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
15441 .channel_mode = alc861vd_3stack_2ch_modes,
15442 .input_mux = &alc861vd_capture_source,
15443 },
15444 [ALC861VD_6ST_DIG] = {
15445 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
15446 .init_verbs = { alc861vd_volume_init_verbs,
15447 alc861vd_6stack_init_verbs },
15448 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
15449 .dac_nids = alc861vd_dac_nids,
15450 .dig_out_nid = ALC861VD_DIGOUT_NID,
15451 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
15452 .channel_mode = alc861vd_6stack_modes,
15453 .input_mux = &alc861vd_capture_source,
15454 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020015455 [ALC861VD_LENOVO] = {
15456 .mixers = { alc861vd_lenovo_mixer },
15457 .init_verbs = { alc861vd_volume_init_verbs,
15458 alc861vd_3stack_init_verbs,
15459 alc861vd_eapd_verbs,
15460 alc861vd_lenovo_unsol_verbs },
15461 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
15462 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020015463 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
15464 .channel_mode = alc861vd_3stack_2ch_modes,
15465 .input_mux = &alc861vd_capture_source,
15466 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020015467 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015468 .init_hook = alc861vd_lenovo_init_hook,
Kailang Yangbdd148a2007-05-08 15:19:08 +020015469 },
Kailang Yang272a5272007-05-14 11:00:38 +020015470 [ALC861VD_DALLAS] = {
15471 .mixers = { alc861vd_dallas_mixer },
15472 .init_verbs = { alc861vd_dallas_verbs },
15473 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
15474 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020015475 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
15476 .channel_mode = alc861vd_3stack_2ch_modes,
15477 .input_mux = &alc861vd_dallas_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015478 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020015479 .setup = alc861vd_dallas_setup,
15480 .init_hook = alc_automute_amp,
Kailang Yangd1a991a2007-08-15 16:21:59 +020015481 },
15482 [ALC861VD_HP] = {
15483 .mixers = { alc861vd_hp_mixer },
15484 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
15485 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
15486 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020015487 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020015488 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
15489 .channel_mode = alc861vd_3stack_2ch_modes,
15490 .input_mux = &alc861vd_hp_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015491 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020015492 .setup = alc861vd_dallas_setup,
15493 .init_hook = alc_automute_amp,
Kailang Yangea1fb292008-08-26 12:58:38 +020015494 },
Takashi Iwai13c94742008-11-05 08:06:08 +010015495 [ALC660VD_ASUS_V1S] = {
15496 .mixers = { alc861vd_lenovo_mixer },
15497 .init_verbs = { alc861vd_volume_init_verbs,
15498 alc861vd_3stack_init_verbs,
15499 alc861vd_eapd_verbs,
15500 alc861vd_lenovo_unsol_verbs },
15501 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
15502 .dac_nids = alc660vd_dac_nids,
15503 .dig_out_nid = ALC861VD_DIGOUT_NID,
15504 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
15505 .channel_mode = alc861vd_3stack_2ch_modes,
15506 .input_mux = &alc861vd_capture_source,
15507 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020015508 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015509 .init_hook = alc861vd_lenovo_init_hook,
Takashi Iwai13c94742008-11-05 08:06:08 +010015510 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015511};
15512
15513/*
15514 * BIOS auto configuration
15515 */
Takashi Iwai05f5f472009-08-25 13:10:18 +020015516static int alc861vd_auto_create_input_ctls(struct hda_codec *codec,
15517 const struct auto_pin_cfg *cfg)
15518{
15519 return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x09, 0);
15520}
15521
15522
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015523static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
15524 hda_nid_t nid, int pin_type, int dac_idx)
15525{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015526 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015527}
15528
15529static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
15530{
15531 struct alc_spec *spec = codec->spec;
15532 int i;
15533
15534 for (i = 0; i <= HDA_SIDE; i++) {
15535 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015536 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015537 if (nid)
15538 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015539 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015540 }
15541}
15542
15543
15544static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
15545{
15546 struct alc_spec *spec = codec->spec;
15547 hda_nid_t pin;
15548
15549 pin = spec->autocfg.hp_pins[0];
Sasha Alexandrdef319f2009-06-16 16:00:15 -040015550 if (pin) /* connect to front and use dac 0 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015551 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015552 pin = spec->autocfg.speaker_pins[0];
15553 if (pin)
15554 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015555}
15556
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015557#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
15558
15559static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
15560{
15561 struct alc_spec *spec = codec->spec;
15562 int i;
15563
15564 for (i = 0; i < AUTO_PIN_LAST; i++) {
15565 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai05f5f472009-08-25 13:10:18 +020015566 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +010015567 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +010015568 if (nid != ALC861VD_PIN_CD_NID &&
15569 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015570 snd_hda_codec_write(codec, nid, 0,
15571 AC_VERB_SET_AMP_GAIN_MUTE,
15572 AMP_OUT_MUTE);
15573 }
15574 }
15575}
15576
Takashi Iwaif511b012008-08-15 16:46:42 +020015577#define alc861vd_auto_init_input_src alc882_auto_init_input_src
15578
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015579#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
15580#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
15581
15582/* add playback controls from the parsed DAC table */
15583/* Based on ALC880 version. But ALC861VD has separate,
15584 * different NIDs for mute/unmute switch and volume control */
15585static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
15586 const struct auto_pin_cfg *cfg)
15587{
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015588 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
15589 hda_nid_t nid_v, nid_s;
15590 int i, err;
15591
15592 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015593 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015594 continue;
15595 nid_v = alc861vd_idx_to_mixer_vol(
15596 alc880_dac_to_idx(
15597 spec->multiout.dac_nids[i]));
15598 nid_s = alc861vd_idx_to_mixer_switch(
15599 alc880_dac_to_idx(
15600 spec->multiout.dac_nids[i]));
15601
15602 if (i == 2) {
15603 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015604 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
15605 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015606 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
15607 HDA_OUTPUT));
15608 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015609 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015610 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
15611 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015612 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
15613 HDA_OUTPUT));
15614 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015615 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015616 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
15617 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015618 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
15619 HDA_INPUT));
15620 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015621 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015622 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
15623 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015624 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
15625 HDA_INPUT));
15626 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015627 return err;
15628 } else {
Takashi Iwaia4fcd492009-08-25 16:12:15 +020015629 const char *pfx;
15630 if (cfg->line_outs == 1 &&
15631 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
15632 if (!cfg->hp_pins)
15633 pfx = "Speaker";
15634 else
15635 pfx = "PCM";
15636 } else
15637 pfx = chname[i];
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015638 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015639 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
15640 HDA_OUTPUT));
15641 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015642 return err;
Takashi Iwaia4fcd492009-08-25 16:12:15 +020015643 if (cfg->line_outs == 1 &&
15644 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
15645 pfx = "Speaker";
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015646 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Kailang Yangbdd148a2007-05-08 15:19:08 +020015647 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015648 HDA_INPUT));
15649 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015650 return err;
15651 }
15652 }
15653 return 0;
15654}
15655
15656/* add playback controls for speaker and HP outputs */
15657/* Based on ALC880 version. But ALC861VD has separate,
15658 * different NIDs for mute/unmute switch and volume control */
15659static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
15660 hda_nid_t pin, const char *pfx)
15661{
15662 hda_nid_t nid_v, nid_s;
15663 int err;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015664
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015665 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015666 return 0;
15667
15668 if (alc880_is_fixed_pin(pin)) {
15669 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
15670 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015671 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015672 spec->multiout.hp_nid = nid_v;
15673 else
15674 spec->multiout.extra_out_nid[0] = nid_v;
15675 /* control HP volume/switch on the output mixer amp */
15676 nid_v = alc861vd_idx_to_mixer_vol(
15677 alc880_fixed_pin_idx(pin));
15678 nid_s = alc861vd_idx_to_mixer_switch(
15679 alc880_fixed_pin_idx(pin));
15680
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015681 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015682 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
15683 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015684 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015685 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015686 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
15687 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015688 return err;
15689 } else if (alc880_is_multi_pin(pin)) {
15690 /* set manual connection */
15691 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015692 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015693 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
15694 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015695 return err;
15696 }
15697 return 0;
15698}
15699
15700/* parse the BIOS configuration and set up the alc_spec
15701 * return 1 if successful, 0 if the proper config is not found,
15702 * or a negative error code
15703 * Based on ALC880 version - had to change it to override
15704 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
15705static int alc861vd_parse_auto_config(struct hda_codec *codec)
15706{
15707 struct alc_spec *spec = codec->spec;
15708 int err;
15709 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
15710
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015711 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
15712 alc861vd_ignore);
15713 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015714 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015715 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015716 return 0; /* can't find valid BIOS pin config */
15717
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015718 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
15719 if (err < 0)
15720 return err;
15721 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
15722 if (err < 0)
15723 return err;
15724 err = alc861vd_auto_create_extra_out(spec,
15725 spec->autocfg.speaker_pins[0],
15726 "Speaker");
15727 if (err < 0)
15728 return err;
15729 err = alc861vd_auto_create_extra_out(spec,
15730 spec->autocfg.hp_pins[0],
15731 "Headphone");
15732 if (err < 0)
15733 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020015734 err = alc861vd_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015735 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015736 return err;
15737
15738 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
15739
Takashi Iwai0852d7a2009-02-11 11:35:15 +010015740 if (spec->autocfg.dig_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015741 spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
15742
Takashi Iwai603c4012008-07-30 15:01:44 +020015743 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010015744 add_mixer(spec, spec->kctls.list);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015745
Takashi Iwaid88897e2008-10-31 15:01:37 +010015746 add_verb(spec, alc861vd_volume_init_verbs);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015747
15748 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020015749 spec->input_mux = &spec->private_imux[0];
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015750
Takashi Iwai776e1842007-08-29 15:07:11 +020015751 err = alc_auto_add_mic_boost(codec);
15752 if (err < 0)
15753 return err;
15754
Takashi Iwai4a79ba32009-04-22 16:31:35 +020015755 alc_ssid_check(codec, 0x15, 0x1b, 0x14);
15756
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015757 return 1;
15758}
15759
15760/* additional initialization for auto-configuration model */
15761static void alc861vd_auto_init(struct hda_codec *codec)
15762{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015763 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015764 alc861vd_auto_init_multi_out(codec);
15765 alc861vd_auto_init_hp_out(codec);
15766 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020015767 alc861vd_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015768 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020015769 alc_inithook(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015770}
15771
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020015772enum {
15773 ALC660VD_FIX_ASUS_GPIO1
15774};
15775
15776/* reset GPIO1 */
15777static const struct hda_verb alc660vd_fix_asus_gpio1_verbs[] = {
15778 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
15779 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
15780 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
15781 { }
15782};
15783
15784static const struct alc_fixup alc861vd_fixups[] = {
15785 [ALC660VD_FIX_ASUS_GPIO1] = {
15786 .verbs = alc660vd_fix_asus_gpio1_verbs,
15787 },
15788};
15789
15790static struct snd_pci_quirk alc861vd_fixup_tbl[] = {
15791 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
15792 {}
15793};
15794
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015795static int patch_alc861vd(struct hda_codec *codec)
15796{
15797 struct alc_spec *spec;
15798 int err, board_config;
15799
15800 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
15801 if (spec == NULL)
15802 return -ENOMEM;
15803
15804 codec->spec = spec;
15805
15806 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
15807 alc861vd_models,
15808 alc861vd_cfg_tbl);
15809
15810 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020015811 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
15812 codec->chip_name);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015813 board_config = ALC861VD_AUTO;
15814 }
15815
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020015816 alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups);
15817
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015818 if (board_config == ALC861VD_AUTO) {
15819 /* automatic parse from the BIOS config */
15820 err = alc861vd_parse_auto_config(codec);
15821 if (err < 0) {
15822 alc_free(codec);
15823 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015824 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015825 printk(KERN_INFO
15826 "hda_codec: Cannot set up configuration "
15827 "from BIOS. Using base mode...\n");
15828 board_config = ALC861VD_3ST;
15829 }
15830 }
15831
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090015832 err = snd_hda_attach_beep_device(codec, 0x23);
15833 if (err < 0) {
15834 alc_free(codec);
15835 return err;
15836 }
15837
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015838 if (board_config != ALC861VD_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020015839 setup_preset(codec, &alc861vd_presets[board_config]);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015840
Kailang Yang2f893282008-05-27 12:14:47 +020015841 if (codec->vendor_id == 0x10ec0660) {
Kailang Yangf9423e72008-05-27 12:32:25 +020015842 /* always turn on EAPD */
Takashi Iwaid88897e2008-10-31 15:01:37 +010015843 add_verb(spec, alc660vd_eapd_verbs);
Kailang Yang2f893282008-05-27 12:14:47 +020015844 }
15845
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015846 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
15847 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
15848
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015849 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
15850 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
15851
Takashi Iwaidd704692009-08-11 08:45:11 +020015852 if (!spec->adc_nids) {
15853 spec->adc_nids = alc861vd_adc_nids;
15854 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
15855 }
15856 if (!spec->capsrc_nids)
15857 spec->capsrc_nids = alc861vd_capsrc_nids;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015858
Takashi Iwaib59bdf32009-08-11 09:47:30 +020015859 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010015860 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015861
Takashi Iwai2134ea42008-01-10 16:53:55 +010015862 spec->vmaster_nid = 0x02;
15863
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015864 codec->patch_ops = alc_patch_ops;
15865
15866 if (board_config == ALC861VD_AUTO)
15867 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020015868#ifdef CONFIG_SND_HDA_POWER_SAVE
15869 if (!spec->loopback.amplist)
15870 spec->loopback.amplist = alc861vd_loopbacks;
15871#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010015872 codec->proc_widget_hook = print_realtek_coef;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015873
15874 return 0;
15875}
15876
15877/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015878 * ALC662 support
15879 *
15880 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
15881 * configuration. Each pin widget can choose any input DACs and a mixer.
15882 * Each ADC is connected from a mixer of all inputs. This makes possible
15883 * 6-channel independent captures.
15884 *
15885 * In addition, an independent DAC for the multi-playback (not used in this
15886 * driver yet).
15887 */
15888#define ALC662_DIGOUT_NID 0x06
15889#define ALC662_DIGIN_NID 0x0a
15890
15891static hda_nid_t alc662_dac_nids[4] = {
15892 /* front, rear, clfe, rear_surr */
15893 0x02, 0x03, 0x04
15894};
15895
Kailang Yang622e84c2009-04-21 07:39:04 +020015896static hda_nid_t alc272_dac_nids[2] = {
15897 0x02, 0x03
15898};
15899
Takashi Iwaib59bdf32009-08-11 09:47:30 +020015900static hda_nid_t alc662_adc_nids[2] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015901 /* ADC1-2 */
Takashi Iwaib59bdf32009-08-11 09:47:30 +020015902 0x09, 0x08
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015903};
Takashi Iwaie1406342008-02-11 18:32:32 +010015904
Kailang Yang622e84c2009-04-21 07:39:04 +020015905static hda_nid_t alc272_adc_nids[1] = {
15906 /* ADC1-2 */
15907 0x08,
15908};
15909
Takashi Iwaib59bdf32009-08-11 09:47:30 +020015910static hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 };
Kailang Yang622e84c2009-04-21 07:39:04 +020015911static hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
15912
Takashi Iwaie1406342008-02-11 18:32:32 +010015913
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015914/* input MUX */
15915/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015916static struct hda_input_mux alc662_capture_source = {
15917 .num_items = 4,
15918 .items = {
15919 { "Mic", 0x0 },
15920 { "Front Mic", 0x1 },
15921 { "Line", 0x2 },
15922 { "CD", 0x4 },
15923 },
15924};
15925
15926static struct hda_input_mux alc662_lenovo_101e_capture_source = {
15927 .num_items = 2,
15928 .items = {
15929 { "Mic", 0x1 },
15930 { "Line", 0x2 },
15931 },
15932};
Kailang Yang291702f2007-10-16 14:28:03 +020015933
Kailang Yang6dda9f42008-05-27 12:05:31 +020015934static struct hda_input_mux alc663_capture_source = {
15935 .num_items = 3,
15936 .items = {
15937 { "Mic", 0x0 },
15938 { "Front Mic", 0x1 },
15939 { "Line", 0x2 },
15940 },
15941};
15942
Takashi Iwai4f5d17062009-08-11 18:17:46 +020015943#if 0 /* set to 1 for testing other input sources below */
Chris Pockelé9541ba12009-05-12 08:08:53 +020015944static struct hda_input_mux alc272_nc10_capture_source = {
15945 .num_items = 16,
15946 .items = {
15947 { "Autoselect Mic", 0x0 },
15948 { "Internal Mic", 0x1 },
15949 { "In-0x02", 0x2 },
15950 { "In-0x03", 0x3 },
15951 { "In-0x04", 0x4 },
15952 { "In-0x05", 0x5 },
15953 { "In-0x06", 0x6 },
15954 { "In-0x07", 0x7 },
15955 { "In-0x08", 0x8 },
15956 { "In-0x09", 0x9 },
15957 { "In-0x0a", 0x0a },
15958 { "In-0x0b", 0x0b },
15959 { "In-0x0c", 0x0c },
15960 { "In-0x0d", 0x0d },
15961 { "In-0x0e", 0x0e },
15962 { "In-0x0f", 0x0f },
15963 },
15964};
15965#endif
15966
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015967/*
15968 * 2ch mode
15969 */
15970static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
15971 { 2, NULL }
15972};
15973
15974/*
15975 * 2ch mode
15976 */
15977static struct hda_verb alc662_3ST_ch2_init[] = {
15978 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
15979 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
15980 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
15981 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
15982 { } /* end */
15983};
15984
15985/*
15986 * 6ch mode
15987 */
15988static struct hda_verb alc662_3ST_ch6_init[] = {
15989 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15990 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
15991 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
15992 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15993 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
15994 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
15995 { } /* end */
15996};
15997
15998static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
15999 { 2, alc662_3ST_ch2_init },
16000 { 6, alc662_3ST_ch6_init },
16001};
16002
16003/*
16004 * 2ch mode
16005 */
16006static struct hda_verb alc662_sixstack_ch6_init[] = {
16007 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
16008 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
16009 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16010 { } /* end */
16011};
16012
16013/*
16014 * 6ch mode
16015 */
16016static struct hda_verb alc662_sixstack_ch8_init[] = {
16017 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16018 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16019 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16020 { } /* end */
16021};
16022
16023static struct hda_channel_mode alc662_5stack_modes[2] = {
16024 { 2, alc662_sixstack_ch6_init },
16025 { 6, alc662_sixstack_ch8_init },
16026};
16027
16028/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
16029 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
16030 */
16031
16032static struct snd_kcontrol_new alc662_base_mixer[] = {
16033 /* output mixer control */
16034 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016035 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016036 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016037 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016038 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
16039 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016040 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
16041 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016042 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16043
16044 /*Input mixer control */
16045 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
16046 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
16047 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
16048 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
16049 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
16050 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
16051 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
16052 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016053 { } /* end */
16054};
16055
16056static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
16057 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016058 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016059 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16060 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16061 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16062 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16063 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16064 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16065 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16066 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16067 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016068 { } /* end */
16069};
16070
16071static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
16072 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016073 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016074 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016075 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016076 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
16077 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016078 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
16079 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016080 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16081 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16082 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16083 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16084 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16085 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16086 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16087 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16088 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016089 { } /* end */
16090};
16091
16092static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
16093 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16094 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010016095 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16096 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016097 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16098 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16099 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16100 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16101 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016102 { } /* end */
16103};
16104
Kailang Yang291702f2007-10-16 14:28:03 +020016105static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020016106 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16107 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang291702f2007-10-16 14:28:03 +020016108
16109 HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
16110 HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16111 HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16112
16113 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
16114 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16115 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16116 { } /* end */
16117};
16118
Kailang Yang8c427222008-01-10 13:03:59 +010016119static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020016120 ALC262_HIPPO_MASTER_SWITCH,
16121 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010016122 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010016123 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
16124 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010016125 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
16126 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16127 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16128 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16129 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16130 { } /* end */
16131};
16132
Kailang Yangf1d4e282008-08-26 14:03:29 +020016133static struct hda_bind_ctls alc663_asus_bind_master_vol = {
16134 .ops = &snd_hda_bind_vol,
16135 .values = {
16136 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
16137 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
16138 0
16139 },
16140};
16141
16142static struct hda_bind_ctls alc663_asus_one_bind_switch = {
16143 .ops = &snd_hda_bind_sw,
16144 .values = {
16145 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
16146 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
16147 0
16148 },
16149};
16150
Kailang Yang6dda9f42008-05-27 12:05:31 +020016151static struct snd_kcontrol_new alc663_m51va_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020016152 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
16153 HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
16154 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16155 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16156 { } /* end */
16157};
16158
16159static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
16160 .ops = &snd_hda_bind_sw,
16161 .values = {
16162 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
16163 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
16164 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
16165 0
16166 },
16167};
16168
16169static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
16170 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
16171 HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
16172 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16173 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16174 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16175 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16176
16177 { } /* end */
16178};
16179
16180static struct hda_bind_ctls alc663_asus_four_bind_switch = {
16181 .ops = &snd_hda_bind_sw,
16182 .values = {
16183 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
16184 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
16185 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
16186 0
16187 },
16188};
16189
16190static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
16191 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
16192 HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
16193 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16194 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16195 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16196 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16197 { } /* end */
16198};
16199
16200static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020016201 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16202 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020016203 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16204 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16205 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16206 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16207 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16208 { } /* end */
16209};
16210
16211static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
16212 .ops = &snd_hda_bind_vol,
16213 .values = {
16214 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
16215 HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
16216 0
16217 },
16218};
16219
16220static struct hda_bind_ctls alc663_asus_two_bind_switch = {
16221 .ops = &snd_hda_bind_sw,
16222 .values = {
16223 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
16224 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
16225 0
16226 },
16227};
16228
16229static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
16230 HDA_BIND_VOL("Master Playback Volume",
16231 &alc663_asus_two_bind_master_vol),
16232 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
16233 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020016234 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
16235 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16236 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020016237 { } /* end */
16238};
16239
16240static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
16241 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
16242 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
16243 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16244 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
16245 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16246 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020016247 { } /* end */
16248};
16249
16250static struct snd_kcontrol_new alc663_g71v_mixer[] = {
16251 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16252 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
16253 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16254 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
16255 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
16256
16257 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16258 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16259 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16260 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16261 { } /* end */
16262};
16263
16264static struct snd_kcontrol_new alc663_g50v_mixer[] = {
16265 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16266 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
16267 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
16268
16269 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16270 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16271 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16272 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16273 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16274 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16275 { } /* end */
16276};
16277
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016278static struct snd_kcontrol_new alc662_chmode_mixer[] = {
16279 {
16280 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
16281 .name = "Channel Mode",
16282 .info = alc_ch_mode_info,
16283 .get = alc_ch_mode_get,
16284 .put = alc_ch_mode_put,
16285 },
16286 { } /* end */
16287};
16288
16289static struct hda_verb alc662_init_verbs[] = {
16290 /* ADC: mute amp left and right */
16291 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16292 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
16293 /* Front mixer: unmute input/output amp left and right (volume = 0) */
16294
Takashi Iwaicb53c622007-08-10 17:21:45 +020016295 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16296 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16297 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16298 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16299 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016300
Kailang Yangb60dd392007-09-20 12:50:29 +020016301 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16302 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16303 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16304 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16305 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16306 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016307
16308 /* Front Pin: output 0 (0x0c) */
16309 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16310 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16311
16312 /* Rear Pin: output 1 (0x0d) */
16313 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16314 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16315
16316 /* CLFE Pin: output 2 (0x0e) */
16317 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16318 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16319
16320 /* Mic (rear) pin: input vref at 80% */
16321 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16322 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16323 /* Front Mic pin: input vref at 80% */
16324 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16325 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16326 /* Line In pin: input */
16327 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16328 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16329 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16330 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16331 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16332 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16333 /* CD pin widget for input */
16334 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16335
16336 /* FIXME: use matrix-type input source selection */
16337 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
16338 /* Input mixer */
16339 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang291702f2007-10-16 14:28:03 +020016340 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020016341
16342 /* always trun on EAPD */
16343 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16344 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
16345
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016346 { }
16347};
16348
16349static struct hda_verb alc662_sue_init_verbs[] = {
16350 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
16351 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020016352 {}
16353};
16354
16355static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
16356 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16357 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16358 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016359};
16360
Kailang Yang8c427222008-01-10 13:03:59 +010016361/* Set Unsolicited Event*/
16362static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
16363 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16364 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16365 {}
16366};
16367
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016368/*
16369 * generic initialization of ADC, input mixers and output mixers
16370 */
16371static struct hda_verb alc662_auto_init_verbs[] = {
16372 /*
16373 * Unmute ADC and set the default input to mic-in
16374 */
16375 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
16376 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16377
16378 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
16379 * mixer widget
16380 * Note: PASD motherboards uses the Line In 2 as the input for front
16381 * panel mic (mic 2)
16382 */
16383 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020016384 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16385 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16386 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16387 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16388 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016389
16390 /*
16391 * Set up output mixers (0x0c - 0x0f)
16392 */
16393 /* set vol=0 to output mixers */
16394 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16395 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16396 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16397
16398 /* set up input amps for analog loopback */
16399 /* Amp Indices: DAC = 0, mixer = 1 */
Kailang Yangb60dd392007-09-20 12:50:29 +020016400 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16401 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16402 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16403 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16404 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16405 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016406
16407
16408 /* FIXME: use matrix-type input source selection */
16409 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
16410 /* Input mixer */
16411 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangd1a991a2007-08-15 16:21:59 +020016412 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016413 { }
16414};
16415
Takashi Iwai24fb9172008-09-02 14:48:20 +020016416/* additional verbs for ALC663 */
16417static struct hda_verb alc663_auto_init_verbs[] = {
16418 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16419 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16420 { }
16421};
16422
Kailang Yang6dda9f42008-05-27 12:05:31 +020016423static struct hda_verb alc663_m51va_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020016424 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16425 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yang6dda9f42008-05-27 12:05:31 +020016426 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16427 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf1d4e282008-08-26 14:03:29 +020016428 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
16429 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16430 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020016431 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16432 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16433 {}
16434};
16435
Kailang Yangf1d4e282008-08-26 14:03:29 +020016436static struct hda_verb alc663_21jd_amic_init_verbs[] = {
16437 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16438 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16439 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
16440 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16441 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16442 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16443 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16444 {}
16445};
16446
16447static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
16448 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16449 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16450 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16451 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
16452 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16453 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16454 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16455 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16456 {}
16457};
16458
16459static struct hda_verb alc663_15jd_amic_init_verbs[] = {
16460 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16461 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16462 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
16463 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16464 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16465 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16466 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16467 {}
16468};
16469
16470static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
16471 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16472 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16473 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16474 {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
16475 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16476 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16477 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
16478 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16479 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16480 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16481 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16482 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16483 {}
16484};
16485
16486static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
16487 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16488 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16489 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16490 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
16491 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16492 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16493 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
16494 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16495 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16496 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16497 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16498 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16499 {}
16500};
16501
Kailang Yang6dda9f42008-05-27 12:05:31 +020016502static struct hda_verb alc663_g71v_init_verbs[] = {
16503 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16504 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
16505 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
16506
16507 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16508 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16509 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
16510
16511 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
16512 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
16513 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
16514 {}
16515};
16516
16517static struct hda_verb alc663_g50v_init_verbs[] = {
16518 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16519 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16520 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
16521
16522 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16523 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16524 {}
16525};
16526
Kailang Yangf1d4e282008-08-26 14:03:29 +020016527static struct hda_verb alc662_ecs_init_verbs[] = {
16528 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
16529 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16530 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16531 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16532 {}
16533};
16534
Kailang Yang622e84c2009-04-21 07:39:04 +020016535static struct hda_verb alc272_dell_zm1_init_verbs[] = {
16536 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16537 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16538 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16539 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16540 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16541 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16542 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
16543 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16544 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
16545 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16546 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16547 {}
16548};
16549
16550static struct hda_verb alc272_dell_init_verbs[] = {
16551 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16552 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16553 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16554 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16555 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16556 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16557 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
16558 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16559 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
16560 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16561 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16562 {}
16563};
16564
Kailang Yangf1d4e282008-08-26 14:03:29 +020016565static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
16566 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
16567 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
16568 { } /* end */
16569};
16570
Kailang Yang622e84c2009-04-21 07:39:04 +020016571static struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
16572 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
16573 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
16574 { } /* end */
16575};
16576
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016577static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
16578{
16579 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016580 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016581
Wu Fengguang864f92b2009-11-18 12:38:02 +080016582 present = snd_hda_jack_detect(codec, 0x14);
Takashi Iwai47fd8302007-08-10 17:11:07 +020016583 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080016584
Takashi Iwai47fd8302007-08-10 17:11:07 +020016585 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
16586 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016587}
16588
16589static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
16590{
16591 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016592 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016593
Wu Fengguang864f92b2009-11-18 12:38:02 +080016594 present = snd_hda_jack_detect(codec, 0x1b);
Takashi Iwai47fd8302007-08-10 17:11:07 +020016595 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080016596
Takashi Iwai47fd8302007-08-10 17:11:07 +020016597 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
16598 HDA_AMP_MUTE, bits);
16599 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
16600 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016601}
16602
16603static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
16604 unsigned int res)
16605{
16606 if ((res >> 26) == ALC880_HP_EVENT)
16607 alc662_lenovo_101e_all_automute(codec);
16608 if ((res >> 26) == ALC880_FRONT_EVENT)
16609 alc662_lenovo_101e_ispeaker_automute(codec);
16610}
16611
Kailang Yang291702f2007-10-16 14:28:03 +020016612/* unsolicited event for HP jack sensing */
16613static void alc662_eeepc_unsol_event(struct hda_codec *codec,
16614 unsigned int res)
16615{
Kailang Yang291702f2007-10-16 14:28:03 +020016616 if ((res >> 26) == ALC880_MIC_EVENT)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016617 alc_mic_automute(codec);
Takashi Iwai42171c12009-05-08 14:11:43 +020016618 else
16619 alc262_hippo_unsol_event(codec, res);
Kailang Yang291702f2007-10-16 14:28:03 +020016620}
16621
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016622static void alc662_eeepc_setup(struct hda_codec *codec)
Kailang Yang291702f2007-10-16 14:28:03 +020016623{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016624 struct alc_spec *spec = codec->spec;
16625
16626 alc262_hippo1_setup(codec);
16627 spec->ext_mic.pin = 0x18;
16628 spec->ext_mic.mux_idx = 0;
16629 spec->int_mic.pin = 0x19;
16630 spec->int_mic.mux_idx = 1;
16631 spec->auto_mic = 1;
Kailang Yang291702f2007-10-16 14:28:03 +020016632}
16633
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016634static void alc662_eeepc_inithook(struct hda_codec *codec)
16635{
16636 alc262_hippo_automute(codec);
16637 alc_mic_automute(codec);
16638}
16639
16640static void alc662_eeepc_ep20_setup(struct hda_codec *codec)
Kailang Yang8c427222008-01-10 13:03:59 +010016641{
Takashi Iwai42171c12009-05-08 14:11:43 +020016642 struct alc_spec *spec = codec->spec;
16643
16644 spec->autocfg.hp_pins[0] = 0x14;
16645 spec->autocfg.speaker_pins[0] = 0x1b;
Kailang Yang8c427222008-01-10 13:03:59 +010016646}
16647
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016648#define alc662_eeepc_ep20_inithook alc262_hippo_master_update
16649
Kailang Yang6dda9f42008-05-27 12:05:31 +020016650static void alc663_m51va_speaker_automute(struct hda_codec *codec)
16651{
16652 unsigned int present;
16653 unsigned char bits;
16654
Wu Fengguang864f92b2009-11-18 12:38:02 +080016655 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yang6dda9f42008-05-27 12:05:31 +020016656 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yangf1d4e282008-08-26 14:03:29 +020016657 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
16658 AMP_IN_MUTE(0), bits);
16659 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
16660 AMP_IN_MUTE(0), bits);
16661}
16662
16663static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
16664{
16665 unsigned int present;
16666 unsigned char bits;
16667
Wu Fengguang864f92b2009-11-18 12:38:02 +080016668 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yangf1d4e282008-08-26 14:03:29 +020016669 bits = present ? HDA_AMP_MUTE : 0;
16670 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
16671 AMP_IN_MUTE(0), bits);
16672 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
16673 AMP_IN_MUTE(0), bits);
16674 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
16675 AMP_IN_MUTE(0), bits);
16676 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
16677 AMP_IN_MUTE(0), bits);
16678}
16679
16680static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
16681{
16682 unsigned int present;
16683 unsigned char bits;
16684
Wu Fengguang864f92b2009-11-18 12:38:02 +080016685 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020016686 bits = present ? HDA_AMP_MUTE : 0;
16687 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
16688 AMP_IN_MUTE(0), bits);
16689 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
16690 AMP_IN_MUTE(0), bits);
16691 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
16692 AMP_IN_MUTE(0), bits);
16693 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
16694 AMP_IN_MUTE(0), bits);
16695}
16696
16697static void alc662_f5z_speaker_automute(struct hda_codec *codec)
16698{
16699 unsigned int present;
16700 unsigned char bits;
16701
Wu Fengguang864f92b2009-11-18 12:38:02 +080016702 present = snd_hda_jack_detect(codec, 0x1b);
Kailang Yangf1d4e282008-08-26 14:03:29 +020016703 bits = present ? 0 : PIN_OUT;
16704 snd_hda_codec_write(codec, 0x14, 0,
16705 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
16706}
16707
16708static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
16709{
16710 unsigned int present1, present2;
16711
Wu Fengguang864f92b2009-11-18 12:38:02 +080016712 present1 = snd_hda_jack_detect(codec, 0x21);
16713 present2 = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020016714
16715 if (present1 || present2) {
16716 snd_hda_codec_write_cache(codec, 0x14, 0,
16717 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
16718 } else {
16719 snd_hda_codec_write_cache(codec, 0x14, 0,
16720 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
16721 }
16722}
16723
16724static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
16725{
16726 unsigned int present1, present2;
16727
Wu Fengguang864f92b2009-11-18 12:38:02 +080016728 present1 = snd_hda_jack_detect(codec, 0x1b);
16729 present2 = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020016730
16731 if (present1 || present2) {
16732 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
16733 AMP_IN_MUTE(0), AMP_IN_MUTE(0));
16734 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
16735 AMP_IN_MUTE(0), AMP_IN_MUTE(0));
16736 } else {
16737 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
16738 AMP_IN_MUTE(0), 0);
16739 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
16740 AMP_IN_MUTE(0), 0);
16741 }
Kailang Yang6dda9f42008-05-27 12:05:31 +020016742}
16743
Kailang Yang6dda9f42008-05-27 12:05:31 +020016744static void alc663_m51va_unsol_event(struct hda_codec *codec,
16745 unsigned int res)
16746{
16747 switch (res >> 26) {
16748 case ALC880_HP_EVENT:
16749 alc663_m51va_speaker_automute(codec);
16750 break;
16751 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016752 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020016753 break;
16754 }
16755}
16756
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016757static void alc663_m51va_setup(struct hda_codec *codec)
16758{
16759 struct alc_spec *spec = codec->spec;
16760 spec->ext_mic.pin = 0x18;
16761 spec->ext_mic.mux_idx = 0;
16762 spec->int_mic.pin = 0x12;
16763 spec->int_mic.mux_idx = 1;
16764 spec->auto_mic = 1;
16765}
16766
Kailang Yang6dda9f42008-05-27 12:05:31 +020016767static void alc663_m51va_inithook(struct hda_codec *codec)
16768{
16769 alc663_m51va_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016770 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020016771}
16772
Kailang Yangf1d4e282008-08-26 14:03:29 +020016773/* ***************** Mode1 ******************************/
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016774#define alc663_mode1_unsol_event alc663_m51va_unsol_event
16775#define alc663_mode1_setup alc663_m51va_setup
16776#define alc663_mode1_inithook alc663_m51va_inithook
Kailang Yangf1d4e282008-08-26 14:03:29 +020016777
Kailang Yangf1d4e282008-08-26 14:03:29 +020016778/* ***************** Mode2 ******************************/
16779static void alc662_mode2_unsol_event(struct hda_codec *codec,
16780 unsigned int res)
16781{
16782 switch (res >> 26) {
16783 case ALC880_HP_EVENT:
16784 alc662_f5z_speaker_automute(codec);
16785 break;
16786 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016787 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020016788 break;
16789 }
16790}
16791
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016792#define alc662_mode2_setup alc663_m51va_setup
16793
Kailang Yangf1d4e282008-08-26 14:03:29 +020016794static void alc662_mode2_inithook(struct hda_codec *codec)
16795{
16796 alc662_f5z_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016797 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020016798}
16799/* ***************** Mode3 ******************************/
16800static void alc663_mode3_unsol_event(struct hda_codec *codec,
16801 unsigned int res)
16802{
16803 switch (res >> 26) {
16804 case ALC880_HP_EVENT:
16805 alc663_two_hp_m1_speaker_automute(codec);
16806 break;
16807 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016808 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020016809 break;
16810 }
16811}
16812
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016813#define alc663_mode3_setup alc663_m51va_setup
16814
Kailang Yangf1d4e282008-08-26 14:03:29 +020016815static void alc663_mode3_inithook(struct hda_codec *codec)
16816{
16817 alc663_two_hp_m1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016818 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020016819}
16820/* ***************** Mode4 ******************************/
16821static void alc663_mode4_unsol_event(struct hda_codec *codec,
16822 unsigned int res)
16823{
16824 switch (res >> 26) {
16825 case ALC880_HP_EVENT:
16826 alc663_21jd_two_speaker_automute(codec);
16827 break;
16828 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016829 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020016830 break;
16831 }
16832}
16833
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016834#define alc663_mode4_setup alc663_m51va_setup
16835
Kailang Yangf1d4e282008-08-26 14:03:29 +020016836static void alc663_mode4_inithook(struct hda_codec *codec)
16837{
16838 alc663_21jd_two_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016839 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020016840}
16841/* ***************** Mode5 ******************************/
16842static void alc663_mode5_unsol_event(struct hda_codec *codec,
16843 unsigned int res)
16844{
16845 switch (res >> 26) {
16846 case ALC880_HP_EVENT:
16847 alc663_15jd_two_speaker_automute(codec);
16848 break;
16849 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016850 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020016851 break;
16852 }
16853}
16854
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016855#define alc663_mode5_setup alc663_m51va_setup
16856
Kailang Yangf1d4e282008-08-26 14:03:29 +020016857static void alc663_mode5_inithook(struct hda_codec *codec)
16858{
16859 alc663_15jd_two_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016860 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020016861}
16862/* ***************** Mode6 ******************************/
16863static void alc663_mode6_unsol_event(struct hda_codec *codec,
16864 unsigned int res)
16865{
16866 switch (res >> 26) {
16867 case ALC880_HP_EVENT:
16868 alc663_two_hp_m2_speaker_automute(codec);
16869 break;
16870 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016871 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020016872 break;
16873 }
16874}
16875
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016876#define alc663_mode6_setup alc663_m51va_setup
16877
Kailang Yangf1d4e282008-08-26 14:03:29 +020016878static void alc663_mode6_inithook(struct hda_codec *codec)
16879{
16880 alc663_two_hp_m2_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016881 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020016882}
16883
Kailang Yang6dda9f42008-05-27 12:05:31 +020016884static void alc663_g71v_hp_automute(struct hda_codec *codec)
16885{
16886 unsigned int present;
16887 unsigned char bits;
16888
Wu Fengguang864f92b2009-11-18 12:38:02 +080016889 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yang6dda9f42008-05-27 12:05:31 +020016890 bits = present ? HDA_AMP_MUTE : 0;
16891 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
16892 HDA_AMP_MUTE, bits);
16893 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
16894 HDA_AMP_MUTE, bits);
16895}
16896
16897static void alc663_g71v_front_automute(struct hda_codec *codec)
16898{
16899 unsigned int present;
16900 unsigned char bits;
16901
Wu Fengguang864f92b2009-11-18 12:38:02 +080016902 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yang6dda9f42008-05-27 12:05:31 +020016903 bits = present ? HDA_AMP_MUTE : 0;
16904 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
16905 HDA_AMP_MUTE, bits);
16906}
16907
16908static void alc663_g71v_unsol_event(struct hda_codec *codec,
16909 unsigned int res)
16910{
16911 switch (res >> 26) {
16912 case ALC880_HP_EVENT:
16913 alc663_g71v_hp_automute(codec);
16914 break;
16915 case ALC880_FRONT_EVENT:
16916 alc663_g71v_front_automute(codec);
16917 break;
16918 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016919 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020016920 break;
16921 }
16922}
16923
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016924#define alc663_g71v_setup alc663_m51va_setup
16925
Kailang Yang6dda9f42008-05-27 12:05:31 +020016926static void alc663_g71v_inithook(struct hda_codec *codec)
16927{
16928 alc663_g71v_front_automute(codec);
16929 alc663_g71v_hp_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016930 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020016931}
16932
16933static void alc663_g50v_unsol_event(struct hda_codec *codec,
16934 unsigned int res)
16935{
16936 switch (res >> 26) {
16937 case ALC880_HP_EVENT:
16938 alc663_m51va_speaker_automute(codec);
16939 break;
16940 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016941 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020016942 break;
16943 }
16944}
16945
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016946#define alc663_g50v_setup alc663_m51va_setup
16947
Kailang Yang6dda9f42008-05-27 12:05:31 +020016948static void alc663_g50v_inithook(struct hda_codec *codec)
16949{
16950 alc663_m51va_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016951 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020016952}
16953
Kailang Yangf1d4e282008-08-26 14:03:29 +020016954static struct snd_kcontrol_new alc662_ecs_mixer[] = {
16955 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020016956 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016957
16958 HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT),
16959 HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
16960 HDA_CODEC_MUTE("e-Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
16961
16962 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
16963 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16964 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16965 { } /* end */
16966};
16967
Chris Pockelé9541ba12009-05-12 08:08:53 +020016968static struct snd_kcontrol_new alc272_nc10_mixer[] = {
16969 /* Master Playback automatically created from Speaker and Headphone */
16970 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16971 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
16972 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16973 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
16974
16975 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16976 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16977 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
16978
16979 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16980 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16981 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
16982 { } /* end */
16983};
16984
Takashi Iwaicb53c622007-08-10 17:21:45 +020016985#ifdef CONFIG_SND_HDA_POWER_SAVE
16986#define alc662_loopbacks alc880_loopbacks
16987#endif
16988
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016989
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016990/* pcm configuration: identical with ALC880 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016991#define alc662_pcm_analog_playback alc880_pcm_analog_playback
16992#define alc662_pcm_analog_capture alc880_pcm_analog_capture
16993#define alc662_pcm_digital_playback alc880_pcm_digital_playback
16994#define alc662_pcm_digital_capture alc880_pcm_digital_capture
16995
16996/*
16997 * configuration and preset
16998 */
16999static const char *alc662_models[ALC662_MODEL_LAST] = {
17000 [ALC662_3ST_2ch_DIG] = "3stack-dig",
17001 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
17002 [ALC662_3ST_6ch] = "3stack-6ch",
17003 [ALC662_5ST_DIG] = "6stack-dig",
17004 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020017005 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010017006 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangf1d4e282008-08-26 14:03:29 +020017007 [ALC662_ECS] = "ecs",
Kailang Yang6dda9f42008-05-27 12:05:31 +020017008 [ALC663_ASUS_M51VA] = "m51va",
17009 [ALC663_ASUS_G71V] = "g71v",
17010 [ALC663_ASUS_H13] = "h13",
17011 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangf1d4e282008-08-26 14:03:29 +020017012 [ALC663_ASUS_MODE1] = "asus-mode1",
17013 [ALC662_ASUS_MODE2] = "asus-mode2",
17014 [ALC663_ASUS_MODE3] = "asus-mode3",
17015 [ALC663_ASUS_MODE4] = "asus-mode4",
17016 [ALC663_ASUS_MODE5] = "asus-mode5",
17017 [ALC663_ASUS_MODE6] = "asus-mode6",
Takashi Iwai01f2bd42009-05-11 08:12:43 +020017018 [ALC272_DELL] = "dell",
17019 [ALC272_DELL_ZM1] = "dell-zm1",
Chris Pockelé9541ba12009-05-12 08:08:53 +020017020 [ALC272_SAMSUNG_NC10] = "samsung-nc10",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017021 [ALC662_AUTO] = "auto",
17022};
17023
17024static struct snd_pci_quirk alc662_cfg_tbl[] = {
Takashi Iwaidea0a502009-02-09 17:14:52 +010017025 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
Kailang Yang622e84c2009-04-21 07:39:04 +020017026 SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
17027 SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017028 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
17029 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
17030 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
17031 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
17032 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
17033 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
17034 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
17035 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
17036 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
17037 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
17038 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
17039 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020017040 SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3),
17041 SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA),
17042 SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017043 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
17044 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
17045 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
17046 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020017047 SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017048 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
17049 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017050 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017051 /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/
17052 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
17053 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020017054 SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1),
17055 SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1),
17056 SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017057 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
17058 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
17059 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020017060 SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017061 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
17062 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020017063 SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017064 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
Kailang Yang80ffe862008-10-15 11:23:27 +020017065 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017066 /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/
17067 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
17068 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020017069 SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017070 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
17071 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010017072 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020017073 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010017074 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017075 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
Herton Ronaldo Krzesinski95fe5f22008-09-26 23:48:45 -030017076 SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
17077 ALC662_3ST_6ch_DIG),
Manoj Iyer3db6c032009-09-22 18:33:29 -050017078 SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB200", ALC663_ASUS_MODE4),
Chris Pockelé9541ba12009-05-12 08:08:53 +020017079 SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
Herton Ronaldo Krzesinskicb559742008-09-26 23:47:45 -030017080 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
17081 ALC662_3ST_6ch_DIG),
Vedran Miletic19c009a2008-09-29 20:29:25 +020017082 SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
Takashi Iwai5bd37292009-04-21 18:36:30 +020017083 SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017084 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Takashi Iwai238713d2008-10-05 10:57:39 +020017085 SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
Vedran Miletic19c009a2008-09-29 20:29:25 +020017086 ALC662_3ST_6ch_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017087 SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
17088 ALC663_ASUS_H13),
David Santinoli7aee6742009-12-09 12:34:26 +010017089 SND_PCI_QUIRK(0x8086, 0xd604, "Intel mobo", ALC662_3ST_2ch_DIG),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017090 {}
17091};
17092
17093static struct alc_config_preset alc662_presets[] = {
17094 [ALC662_3ST_2ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017095 .mixers = { alc662_3ST_2ch_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017096 .init_verbs = { alc662_init_verbs },
17097 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17098 .dac_nids = alc662_dac_nids,
17099 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017100 .dig_in_nid = ALC662_DIGIN_NID,
17101 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17102 .channel_mode = alc662_3ST_2ch_modes,
17103 .input_mux = &alc662_capture_source,
17104 },
17105 [ALC662_3ST_6ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017106 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017107 .init_verbs = { alc662_init_verbs },
17108 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17109 .dac_nids = alc662_dac_nids,
17110 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017111 .dig_in_nid = ALC662_DIGIN_NID,
17112 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
17113 .channel_mode = alc662_3ST_6ch_modes,
17114 .need_dac_fix = 1,
17115 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017116 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017117 [ALC662_3ST_6ch] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017118 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017119 .init_verbs = { alc662_init_verbs },
17120 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17121 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017122 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
17123 .channel_mode = alc662_3ST_6ch_modes,
17124 .need_dac_fix = 1,
17125 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017126 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017127 [ALC662_5ST_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017128 .mixers = { alc662_base_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017129 .init_verbs = { alc662_init_verbs },
17130 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17131 .dac_nids = alc662_dac_nids,
17132 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017133 .dig_in_nid = ALC662_DIGIN_NID,
17134 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
17135 .channel_mode = alc662_5stack_modes,
17136 .input_mux = &alc662_capture_source,
17137 },
17138 [ALC662_LENOVO_101E] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017139 .mixers = { alc662_lenovo_101e_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017140 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
17141 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17142 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017143 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17144 .channel_mode = alc662_3ST_2ch_modes,
17145 .input_mux = &alc662_lenovo_101e_capture_source,
17146 .unsol_event = alc662_lenovo_101e_unsol_event,
17147 .init_hook = alc662_lenovo_101e_all_automute,
17148 },
Kailang Yang291702f2007-10-16 14:28:03 +020017149 [ALC662_ASUS_EEEPC_P701] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017150 .mixers = { alc662_eeepc_p701_mixer },
Kailang Yang291702f2007-10-16 14:28:03 +020017151 .init_verbs = { alc662_init_verbs,
17152 alc662_eeepc_sue_init_verbs },
17153 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17154 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020017155 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17156 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang291702f2007-10-16 14:28:03 +020017157 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017158 .setup = alc662_eeepc_setup,
Kailang Yang291702f2007-10-16 14:28:03 +020017159 .init_hook = alc662_eeepc_inithook,
17160 },
Kailang Yang8c427222008-01-10 13:03:59 +010017161 [ALC662_ASUS_EEEPC_EP20] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017162 .mixers = { alc662_eeepc_ep20_mixer,
Kailang Yang8c427222008-01-10 13:03:59 +010017163 alc662_chmode_mixer },
17164 .init_verbs = { alc662_init_verbs,
17165 alc662_eeepc_ep20_sue_init_verbs },
17166 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17167 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010017168 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
17169 .channel_mode = alc662_3ST_6ch_modes,
17170 .input_mux = &alc662_lenovo_101e_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020017171 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017172 .setup = alc662_eeepc_ep20_setup,
Kailang Yang8c427222008-01-10 13:03:59 +010017173 .init_hook = alc662_eeepc_ep20_inithook,
17174 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020017175 [ALC662_ECS] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017176 .mixers = { alc662_ecs_mixer },
Kailang Yangf1d4e282008-08-26 14:03:29 +020017177 .init_verbs = { alc662_init_verbs,
17178 alc662_ecs_init_verbs },
17179 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17180 .dac_nids = alc662_dac_nids,
17181 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17182 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017183 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017184 .setup = alc662_eeepc_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017185 .init_hook = alc662_eeepc_inithook,
17186 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020017187 [ALC663_ASUS_M51VA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017188 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020017189 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
17190 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17191 .dac_nids = alc662_dac_nids,
17192 .dig_out_nid = ALC662_DIGOUT_NID,
17193 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17194 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020017195 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017196 .setup = alc663_m51va_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020017197 .init_hook = alc663_m51va_inithook,
17198 },
17199 [ALC663_ASUS_G71V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017200 .mixers = { alc663_g71v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020017201 .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
17202 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17203 .dac_nids = alc662_dac_nids,
17204 .dig_out_nid = ALC662_DIGOUT_NID,
17205 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17206 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020017207 .unsol_event = alc663_g71v_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017208 .setup = alc663_g71v_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020017209 .init_hook = alc663_g71v_inithook,
17210 },
17211 [ALC663_ASUS_H13] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017212 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020017213 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
17214 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17215 .dac_nids = alc662_dac_nids,
17216 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17217 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020017218 .unsol_event = alc663_m51va_unsol_event,
17219 .init_hook = alc663_m51va_inithook,
17220 },
17221 [ALC663_ASUS_G50V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017222 .mixers = { alc663_g50v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020017223 .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
17224 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17225 .dac_nids = alc662_dac_nids,
17226 .dig_out_nid = ALC662_DIGOUT_NID,
17227 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
17228 .channel_mode = alc662_3ST_6ch_modes,
17229 .input_mux = &alc663_capture_source,
17230 .unsol_event = alc663_g50v_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017231 .setup = alc663_g50v_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020017232 .init_hook = alc663_g50v_inithook,
17233 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020017234 [ALC663_ASUS_MODE1] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017235 .mixers = { alc663_m51va_mixer },
17236 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017237 .init_verbs = { alc662_init_verbs,
17238 alc663_21jd_amic_init_verbs },
17239 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17240 .hp_nid = 0x03,
17241 .dac_nids = alc662_dac_nids,
17242 .dig_out_nid = ALC662_DIGOUT_NID,
17243 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17244 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017245 .unsol_event = alc663_mode1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017246 .setup = alc663_mode1_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017247 .init_hook = alc663_mode1_inithook,
17248 },
17249 [ALC662_ASUS_MODE2] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017250 .mixers = { alc662_1bjd_mixer },
17251 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017252 .init_verbs = { alc662_init_verbs,
17253 alc662_1bjd_amic_init_verbs },
17254 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17255 .dac_nids = alc662_dac_nids,
17256 .dig_out_nid = ALC662_DIGOUT_NID,
17257 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17258 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017259 .unsol_event = alc662_mode2_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017260 .setup = alc662_mode2_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017261 .init_hook = alc662_mode2_inithook,
17262 },
17263 [ALC663_ASUS_MODE3] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017264 .mixers = { alc663_two_hp_m1_mixer },
17265 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017266 .init_verbs = { alc662_init_verbs,
17267 alc663_two_hp_amic_m1_init_verbs },
17268 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17269 .hp_nid = 0x03,
17270 .dac_nids = alc662_dac_nids,
17271 .dig_out_nid = ALC662_DIGOUT_NID,
17272 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17273 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017274 .unsol_event = alc663_mode3_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017275 .setup = alc663_mode3_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017276 .init_hook = alc663_mode3_inithook,
17277 },
17278 [ALC663_ASUS_MODE4] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017279 .mixers = { alc663_asus_21jd_clfe_mixer },
17280 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017281 .init_verbs = { alc662_init_verbs,
17282 alc663_21jd_amic_init_verbs},
17283 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17284 .hp_nid = 0x03,
17285 .dac_nids = alc662_dac_nids,
17286 .dig_out_nid = ALC662_DIGOUT_NID,
17287 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17288 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017289 .unsol_event = alc663_mode4_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017290 .setup = alc663_mode4_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017291 .init_hook = alc663_mode4_inithook,
17292 },
17293 [ALC663_ASUS_MODE5] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017294 .mixers = { alc663_asus_15jd_clfe_mixer },
17295 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017296 .init_verbs = { alc662_init_verbs,
17297 alc663_15jd_amic_init_verbs },
17298 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17299 .hp_nid = 0x03,
17300 .dac_nids = alc662_dac_nids,
17301 .dig_out_nid = ALC662_DIGOUT_NID,
17302 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17303 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017304 .unsol_event = alc663_mode5_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017305 .setup = alc663_mode5_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017306 .init_hook = alc663_mode5_inithook,
17307 },
17308 [ALC663_ASUS_MODE6] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017309 .mixers = { alc663_two_hp_m2_mixer },
17310 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017311 .init_verbs = { alc662_init_verbs,
17312 alc663_two_hp_amic_m2_init_verbs },
17313 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17314 .hp_nid = 0x03,
17315 .dac_nids = alc662_dac_nids,
17316 .dig_out_nid = ALC662_DIGOUT_NID,
17317 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17318 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017319 .unsol_event = alc663_mode6_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017320 .setup = alc663_mode6_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017321 .init_hook = alc663_mode6_inithook,
17322 },
Kailang Yang622e84c2009-04-21 07:39:04 +020017323 [ALC272_DELL] = {
17324 .mixers = { alc663_m51va_mixer },
17325 .cap_mixer = alc272_auto_capture_mixer,
17326 .init_verbs = { alc662_init_verbs, alc272_dell_init_verbs },
17327 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
17328 .dac_nids = alc662_dac_nids,
17329 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17330 .adc_nids = alc272_adc_nids,
17331 .num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
17332 .capsrc_nids = alc272_capsrc_nids,
17333 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang622e84c2009-04-21 07:39:04 +020017334 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017335 .setup = alc663_m51va_setup,
Kailang Yang622e84c2009-04-21 07:39:04 +020017336 .init_hook = alc663_m51va_inithook,
17337 },
17338 [ALC272_DELL_ZM1] = {
17339 .mixers = { alc663_m51va_mixer },
17340 .cap_mixer = alc662_auto_capture_mixer,
17341 .init_verbs = { alc662_init_verbs, alc272_dell_zm1_init_verbs },
17342 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
17343 .dac_nids = alc662_dac_nids,
17344 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17345 .adc_nids = alc662_adc_nids,
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017346 .num_adc_nids = 1,
Kailang Yang622e84c2009-04-21 07:39:04 +020017347 .capsrc_nids = alc662_capsrc_nids,
17348 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang622e84c2009-04-21 07:39:04 +020017349 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017350 .setup = alc663_m51va_setup,
Kailang Yang622e84c2009-04-21 07:39:04 +020017351 .init_hook = alc663_m51va_inithook,
17352 },
Chris Pockelé9541ba12009-05-12 08:08:53 +020017353 [ALC272_SAMSUNG_NC10] = {
17354 .mixers = { alc272_nc10_mixer },
17355 .init_verbs = { alc662_init_verbs,
17356 alc663_21jd_amic_init_verbs },
17357 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
17358 .dac_nids = alc272_dac_nids,
17359 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17360 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017361 /*.input_mux = &alc272_nc10_capture_source,*/
Chris Pockelé9541ba12009-05-12 08:08:53 +020017362 .unsol_event = alc663_mode4_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017363 .setup = alc663_mode4_setup,
Chris Pockelé9541ba12009-05-12 08:08:53 +020017364 .init_hook = alc663_mode4_inithook,
17365 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017366};
17367
17368
17369/*
17370 * BIOS auto configuration
17371 */
17372
Takashi Iwai7085ec12009-10-02 09:03:58 +020017373/* convert from MIX nid to DAC */
17374static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid)
17375{
17376 if (nid == 0x0f)
17377 return 0x02;
17378 else if (nid >= 0x0c && nid <= 0x0e)
17379 return nid - 0x0c + 0x02;
17380 else
17381 return 0;
17382}
17383
17384/* get MIX nid connected to the given pin targeted to DAC */
17385static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
17386 hda_nid_t dac)
17387{
17388 hda_nid_t mix[4];
17389 int i, num;
17390
17391 num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
17392 for (i = 0; i < num; i++) {
17393 if (alc662_mix_to_dac(mix[i]) == dac)
17394 return mix[i];
17395 }
17396 return 0;
17397}
17398
17399/* look for an empty DAC slot */
17400static hda_nid_t alc662_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
17401{
17402 struct alc_spec *spec = codec->spec;
17403 hda_nid_t srcs[5];
17404 int i, j, num;
17405
17406 num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
17407 if (num < 0)
17408 return 0;
17409 for (i = 0; i < num; i++) {
17410 hda_nid_t nid = alc662_mix_to_dac(srcs[i]);
17411 if (!nid)
17412 continue;
17413 for (j = 0; j < spec->multiout.num_dacs; j++)
17414 if (spec->multiout.dac_nids[j] == nid)
17415 break;
17416 if (j >= spec->multiout.num_dacs)
17417 return nid;
17418 }
17419 return 0;
17420}
17421
17422/* fill in the dac_nids table from the parsed pin configuration */
17423static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
17424 const struct auto_pin_cfg *cfg)
17425{
17426 struct alc_spec *spec = codec->spec;
17427 int i;
17428 hda_nid_t dac;
17429
17430 spec->multiout.dac_nids = spec->private_dac_nids;
17431 for (i = 0; i < cfg->line_outs; i++) {
17432 dac = alc662_look_for_dac(codec, cfg->line_out_pins[i]);
17433 if (!dac)
17434 continue;
17435 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
17436 }
17437 return 0;
17438}
17439
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017440static inline int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020017441 hda_nid_t nid, unsigned int chs)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017442{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017443 return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020017444 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
17445}
17446
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017447static inline int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020017448 hda_nid_t nid, unsigned int chs)
17449{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017450 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020017451 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
17452}
17453
17454#define alc662_add_stereo_vol(spec, pfx, nid) \
17455 alc662_add_vol_ctl(spec, pfx, nid, 3)
17456#define alc662_add_stereo_sw(spec, pfx, nid) \
17457 alc662_add_sw_ctl(spec, pfx, nid, 3)
17458
17459/* add playback controls from the parsed DAC table */
17460static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
17461 const struct auto_pin_cfg *cfg)
17462{
17463 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017464 static const char *chname[4] = {
17465 "Front", "Surround", NULL /*CLFE*/, "Side"
17466 };
Takashi Iwai7085ec12009-10-02 09:03:58 +020017467 hda_nid_t nid, mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017468 int i, err;
17469
17470 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020017471 nid = spec->multiout.dac_nids[i];
17472 if (!nid)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017473 continue;
Takashi Iwai7085ec12009-10-02 09:03:58 +020017474 mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid);
17475 if (!mix)
17476 continue;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017477 if (i == 2) {
17478 /* Center/LFE */
Takashi Iwai7085ec12009-10-02 09:03:58 +020017479 err = alc662_add_vol_ctl(spec, "Center", nid, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017480 if (err < 0)
17481 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020017482 err = alc662_add_vol_ctl(spec, "LFE", nid, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017483 if (err < 0)
17484 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020017485 err = alc662_add_sw_ctl(spec, "Center", mix, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017486 if (err < 0)
17487 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020017488 err = alc662_add_sw_ctl(spec, "LFE", mix, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017489 if (err < 0)
17490 return err;
17491 } else {
Takashi Iwai0d884cb2009-08-25 16:14:35 +020017492 const char *pfx;
17493 if (cfg->line_outs == 1 &&
17494 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020017495 if (cfg->hp_outs)
Takashi Iwai0d884cb2009-08-25 16:14:35 +020017496 pfx = "Speaker";
17497 else
17498 pfx = "PCM";
17499 } else
17500 pfx = chname[i];
Takashi Iwai7085ec12009-10-02 09:03:58 +020017501 err = alc662_add_vol_ctl(spec, pfx, nid, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017502 if (err < 0)
17503 return err;
Takashi Iwai0d884cb2009-08-25 16:14:35 +020017504 if (cfg->line_outs == 1 &&
17505 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
17506 pfx = "Speaker";
Takashi Iwai7085ec12009-10-02 09:03:58 +020017507 err = alc662_add_sw_ctl(spec, pfx, mix, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017508 if (err < 0)
17509 return err;
17510 }
17511 }
17512 return 0;
17513}
17514
17515/* add playback controls for speaker and HP outputs */
Takashi Iwai7085ec12009-10-02 09:03:58 +020017516/* return DAC nid if any new DAC is assigned */
17517static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017518 const char *pfx)
17519{
Takashi Iwai7085ec12009-10-02 09:03:58 +020017520 struct alc_spec *spec = codec->spec;
17521 hda_nid_t nid, mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017522 int err;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017523
17524 if (!pin)
17525 return 0;
Takashi Iwai7085ec12009-10-02 09:03:58 +020017526 nid = alc662_look_for_dac(codec, pin);
17527 if (!nid) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020017528 /* the corresponding DAC is already occupied */
17529 if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
17530 return 0; /* no way */
17531 /* create a switch only */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017532 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020017533 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
17534 }
17535
17536 mix = alc662_dac_to_mix(codec, pin, nid);
17537 if (!mix)
17538 return 0;
17539 err = alc662_add_vol_ctl(spec, pfx, nid, 3);
17540 if (err < 0)
Takashi Iwai24fb9172008-09-02 14:48:20 +020017541 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020017542 err = alc662_add_sw_ctl(spec, pfx, mix, 3);
17543 if (err < 0)
17544 return err;
17545 return nid;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017546}
17547
17548/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020017549#define alc662_auto_create_input_ctls \
Takashi Iwai4b7348a2009-10-14 18:25:23 +020017550 alc882_auto_create_input_ctls
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017551
17552static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
17553 hda_nid_t nid, int pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020017554 hda_nid_t dac)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017555{
Takashi Iwai7085ec12009-10-02 09:03:58 +020017556 int i, num;
17557 hda_nid_t srcs[4];
17558
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017559 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017560 /* need the manual connection? */
Takashi Iwai7085ec12009-10-02 09:03:58 +020017561 num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
17562 if (num <= 1)
17563 return;
17564 for (i = 0; i < num; i++) {
17565 if (alc662_mix_to_dac(srcs[i]) != dac)
17566 continue;
17567 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
17568 return;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017569 }
17570}
17571
17572static void alc662_auto_init_multi_out(struct hda_codec *codec)
17573{
17574 struct alc_spec *spec = codec->spec;
Takashi Iwai7085ec12009-10-02 09:03:58 +020017575 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017576 int i;
17577
17578 for (i = 0; i <= HDA_SIDE; i++) {
17579 hda_nid_t nid = spec->autocfg.line_out_pins[i];
17580 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020017581 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020017582 spec->multiout.dac_nids[i]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017583 }
17584}
17585
17586static void alc662_auto_init_hp_out(struct hda_codec *codec)
17587{
17588 struct alc_spec *spec = codec->spec;
17589 hda_nid_t pin;
17590
17591 pin = spec->autocfg.hp_pins[0];
Takashi Iwai7085ec12009-10-02 09:03:58 +020017592 if (pin)
17593 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP,
17594 spec->multiout.hp_nid);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017595 pin = spec->autocfg.speaker_pins[0];
17596 if (pin)
Takashi Iwai7085ec12009-10-02 09:03:58 +020017597 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT,
17598 spec->multiout.extra_out_nid[0]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017599}
17600
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017601#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
17602
17603static void alc662_auto_init_analog_input(struct hda_codec *codec)
17604{
17605 struct alc_spec *spec = codec->spec;
17606 int i;
17607
17608 for (i = 0; i < AUTO_PIN_LAST; i++) {
17609 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai05f5f472009-08-25 13:10:18 +020017610 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +010017611 alc_set_input_pin(codec, nid, i);
Takashi Iwai52ca15b2009-03-23 12:51:55 +010017612 if (nid != ALC662_PIN_CD_NID &&
Takashi Iwaie82c0252009-03-23 15:17:38 +010017613 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017614 snd_hda_codec_write(codec, nid, 0,
17615 AC_VERB_SET_AMP_GAIN_MUTE,
17616 AMP_OUT_MUTE);
17617 }
17618 }
17619}
17620
Takashi Iwaif511b012008-08-15 16:46:42 +020017621#define alc662_auto_init_input_src alc882_auto_init_input_src
17622
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017623static int alc662_parse_auto_config(struct hda_codec *codec)
17624{
17625 struct alc_spec *spec = codec->spec;
17626 int err;
17627 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
17628
17629 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
17630 alc662_ignore);
17631 if (err < 0)
17632 return err;
17633 if (!spec->autocfg.line_outs)
17634 return 0; /* can't find valid BIOS pin config */
17635
Takashi Iwai7085ec12009-10-02 09:03:58 +020017636 err = alc662_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017637 if (err < 0)
17638 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020017639 err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017640 if (err < 0)
17641 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020017642 err = alc662_auto_create_extra_out(codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017643 spec->autocfg.speaker_pins[0],
17644 "Speaker");
17645 if (err < 0)
17646 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020017647 if (err)
17648 spec->multiout.extra_out_nid[0] = err;
17649 err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017650 "Headphone");
17651 if (err < 0)
17652 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020017653 if (err)
17654 spec->multiout.hp_nid = err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020017655 err = alc662_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017656 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017657 return err;
17658
17659 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
17660
Takashi Iwai0852d7a2009-02-11 11:35:15 +010017661 if (spec->autocfg.dig_outs)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017662 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
17663
Takashi Iwai603c4012008-07-30 15:01:44 +020017664 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010017665 add_mixer(spec, spec->kctls.list);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017666
17667 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020017668 spec->input_mux = &spec->private_imux[0];
Kailang Yangea1fb292008-08-26 12:58:38 +020017669
Takashi Iwaid88897e2008-10-31 15:01:37 +010017670 add_verb(spec, alc662_auto_init_verbs);
Takashi Iwai24fb9172008-09-02 14:48:20 +020017671 if (codec->vendor_id == 0x10ec0663)
Takashi Iwaid88897e2008-10-31 15:01:37 +010017672 add_verb(spec, alc663_auto_init_verbs);
Takashi Iwaiee979a142008-09-02 15:42:20 +020017673
17674 err = alc_auto_add_mic_boost(codec);
17675 if (err < 0)
17676 return err;
17677
Takashi Iwai4a79ba32009-04-22 16:31:35 +020017678 alc_ssid_check(codec, 0x15, 0x1b, 0x14);
17679
Takashi Iwai8c872862007-06-19 12:11:16 +020017680 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017681}
17682
17683/* additional initialization for auto-configuration model */
17684static void alc662_auto_init(struct hda_codec *codec)
17685{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017686 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017687 alc662_auto_init_multi_out(codec);
17688 alc662_auto_init_hp_out(codec);
17689 alc662_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020017690 alc662_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017691 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020017692 alc_inithook(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017693}
17694
17695static int patch_alc662(struct hda_codec *codec)
17696{
17697 struct alc_spec *spec;
17698 int err, board_config;
17699
17700 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
17701 if (!spec)
17702 return -ENOMEM;
17703
17704 codec->spec = spec;
17705
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020017706 alc_fix_pll_init(codec, 0x20, 0x04, 15);
17707
Kailang Yang274693f2009-12-03 10:07:50 +010017708 if (alc_read_coef_idx(codec, 0)==0x8020){
17709 kfree(codec->chip_name);
17710 codec->chip_name = kstrdup("ALC661", GFP_KERNEL);
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010017711 if (!codec->chip_name) {
17712 alc_free(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010017713 return -ENOMEM;
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010017714 }
Kailang Yang274693f2009-12-03 10:07:50 +010017715 }
17716
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017717 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
17718 alc662_models,
17719 alc662_cfg_tbl);
17720 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020017721 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
17722 codec->chip_name);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017723 board_config = ALC662_AUTO;
17724 }
17725
17726 if (board_config == ALC662_AUTO) {
17727 /* automatic parse from the BIOS config */
17728 err = alc662_parse_auto_config(codec);
17729 if (err < 0) {
17730 alc_free(codec);
17731 return err;
Takashi Iwai8c872862007-06-19 12:11:16 +020017732 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017733 printk(KERN_INFO
17734 "hda_codec: Cannot set up configuration "
17735 "from BIOS. Using base mode...\n");
17736 board_config = ALC662_3ST_2ch_DIG;
17737 }
17738 }
17739
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090017740 err = snd_hda_attach_beep_device(codec, 0x1);
17741 if (err < 0) {
17742 alc_free(codec);
17743 return err;
17744 }
17745
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017746 if (board_config != ALC662_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020017747 setup_preset(codec, &alc662_presets[board_config]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017748
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017749 spec->stream_analog_playback = &alc662_pcm_analog_playback;
17750 spec->stream_analog_capture = &alc662_pcm_analog_capture;
17751
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017752 spec->stream_digital_playback = &alc662_pcm_digital_playback;
17753 spec->stream_digital_capture = &alc662_pcm_digital_capture;
17754
Takashi Iwaidd704692009-08-11 08:45:11 +020017755 if (!spec->adc_nids) {
17756 spec->adc_nids = alc662_adc_nids;
17757 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
17758 }
17759 if (!spec->capsrc_nids)
17760 spec->capsrc_nids = alc662_capsrc_nids;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017761
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017762 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017763 set_capture_mixer(codec);
Takashi Iwaib9591442009-03-16 15:25:00 +010017764 if (codec->vendor_id == 0x10ec0662)
17765 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
17766 else
17767 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017768
Takashi Iwai2134ea42008-01-10 16:53:55 +010017769 spec->vmaster_nid = 0x02;
17770
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017771 codec->patch_ops = alc_patch_ops;
17772 if (board_config == ALC662_AUTO)
17773 spec->init_hook = alc662_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020017774#ifdef CONFIG_SND_HDA_POWER_SAVE
17775 if (!spec->loopback.amplist)
17776 spec->loopback.amplist = alc662_loopbacks;
17777#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010017778 codec->proc_widget_hook = print_realtek_coef;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017779
17780 return 0;
17781}
17782
Kailang Yang274693f2009-12-03 10:07:50 +010017783static int patch_alc888(struct hda_codec *codec)
17784{
17785 if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){
17786 kfree(codec->chip_name);
17787 codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010017788 if (!codec->chip_name) {
17789 alc_free(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010017790 return -ENOMEM;
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010017791 }
17792 return patch_alc662(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010017793 }
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010017794 return patch_alc882(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010017795}
17796
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017797/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070017798 * patch entries
17799 */
Takashi Iwai1289e9e2008-11-27 15:47:11 +010017800static struct hda_codec_preset snd_hda_preset_realtek[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070017801 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010017802 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010017803 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020017804 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010017805 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +020017806 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017807 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017808 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017809 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
17810 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
17811 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017812 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
Takashi Iwai49535502009-06-30 15:28:30 +020017813 .patch = patch_alc882 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017814 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
17815 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020017816 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017817 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070017818 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai49535502009-06-30 15:28:30 +020017819 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
Clive Messer669faba2008-09-30 15:49:13 +020017820 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
Takashi Iwai49535502009-06-30 15:28:30 +020017821 .patch = patch_alc882 },
Takashi Iwaicb308f92008-04-16 14:13:29 +020017822 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai49535502009-06-30 15:28:30 +020017823 .patch = patch_alc882 },
Kailang Yangdf694da2005-12-05 19:42:22 +010017824 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Takashi Iwai49535502009-06-30 15:28:30 +020017825 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 },
Kailang Yang44426082008-10-15 11:18:05 +020017826 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
Takashi Iwai49535502009-06-30 15:28:30 +020017827 .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010017828 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },
Takashi Iwai49535502009-06-30 15:28:30 +020017829 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010017830 { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070017831 {} /* terminator */
17832};
Takashi Iwai1289e9e2008-11-27 15:47:11 +010017833
17834MODULE_ALIAS("snd-hda-codec-id:10ec*");
17835
17836MODULE_LICENSE("GPL");
17837MODULE_DESCRIPTION("Realtek HD-audio codec");
17838
17839static struct hda_codec_preset_list realtek_list = {
17840 .preset = snd_hda_preset_realtek,
17841 .owner = THIS_MODULE,
17842};
17843
17844static int __init patch_realtek_init(void)
17845{
17846 return snd_hda_add_codec_preset(&realtek_list);
17847}
17848
17849static void __exit patch_realtek_exit(void)
17850{
17851 snd_hda_delete_codec_preset(&realtek_list);
17852}
17853
17854module_init(patch_realtek_init)
17855module_exit(patch_realtek_exit)