blob: 8699b7fb45b9af785be9f9a2a03352b9991b8971 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for ALC 260/880/882 codecs
5 *
Kailang Yangdf694da2005-12-05 19:42:22 +01006 * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
7 * PeiSen Hou <pshou@realtek.com.tw>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * Takashi Iwai <tiwai@suse.de>
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01009 * Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * This driver is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This driver is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/init.h>
27#include <linux/delay.h>
28#include <linux/slab.h>
29#include <linux/pci.h>
30#include <sound/core.h>
31#include "hda_codec.h"
32#include "hda_local.h"
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090033#include "hda_beep.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
Kailang Yangccc656c2006-10-17 12:32:26 +020035#define ALC880_FRONT_EVENT 0x01
36#define ALC880_DCVOL_EVENT 0x02
37#define ALC880_HP_EVENT 0x04
38#define ALC880_MIC_EVENT 0x08
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
40/* ALC880 board config type */
41enum {
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 ALC880_3ST,
43 ALC880_3ST_DIG,
44 ALC880_5ST,
45 ALC880_5ST_DIG,
46 ALC880_W810,
Takashi Iwaidfc0ff62005-05-12 14:31:49 +020047 ALC880_Z71V,
Takashi Iwaib6482d42005-06-27 15:32:43 +020048 ALC880_6ST,
Takashi Iwai16ded522005-06-10 19:58:24 +020049 ALC880_6ST_DIG,
50 ALC880_F1734,
51 ALC880_ASUS,
52 ALC880_ASUS_DIG,
53 ALC880_ASUS_W1V,
Kailang Yangdf694da2005-12-05 19:42:22 +010054 ALC880_ASUS_DIG2,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +010055 ALC880_FUJITSU,
Takashi Iwai16ded522005-06-10 19:58:24 +020056 ALC880_UNIWILL_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +020057 ALC880_UNIWILL,
58 ALC880_UNIWILL_P53,
Kailang Yangdf694da2005-12-05 19:42:22 +010059 ALC880_CLEVO,
60 ALC880_TCL_S700,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010061 ALC880_LG,
Takashi Iwaid6815182006-03-23 16:06:23 +010062 ALC880_LG_LW,
Takashi Iwaidf99cd32008-04-25 15:25:04 +020063 ALC880_MEDION_RIM,
Takashi Iwaie9edcee2005-06-13 14:16:38 +020064#ifdef CONFIG_SND_DEBUG
65 ALC880_TEST,
66#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010067 ALC880_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020068 ALC880_MODEL_LAST /* last tag */
69};
70
71/* ALC260 models */
72enum {
73 ALC260_BASIC,
74 ALC260_HP,
Kailang Yang3f878302008-08-26 13:02:23 +020075 ALC260_HP_DC7600,
Kailang Yangdf694da2005-12-05 19:42:22 +010076 ALC260_HP_3013,
77 ALC260_FUJITSU_S702X,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +010078 ALC260_ACER,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020079 ALC260_WILL,
80 ALC260_REPLACER_672V,
Michael Schwingencc959482009-02-22 18:58:45 +010081 ALC260_FAVORIT100,
Jonathan Woithe7cf51e482006-02-09 12:01:26 +010082#ifdef CONFIG_SND_DEBUG
83 ALC260_TEST,
84#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010085 ALC260_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020086 ALC260_MODEL_LAST /* last tag */
Linus Torvalds1da177e2005-04-16 15:20:36 -070087};
88
Kailang Yangdf694da2005-12-05 19:42:22 +010089/* ALC262 models */
90enum {
91 ALC262_BASIC,
Kailang Yangccc656c2006-10-17 12:32:26 +020092 ALC262_HIPPO,
93 ALC262_HIPPO_1,
Takashi Iwai834be882006-03-01 14:16:17 +010094 ALC262_FUJITSU,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020095 ALC262_HP_BPC,
Kailang Yangcd7509a2007-01-26 18:33:17 +010096 ALC262_HP_BPC_D7000_WL,
97 ALC262_HP_BPC_D7000_WF,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010098 ALC262_HP_TC_T5735,
Kailang Yang8c427222008-01-10 13:03:59 +010099 ALC262_HP_RP5700,
Takashi Iwai304dcaa2006-07-25 14:51:16 +0200100 ALC262_BENQ_ED8,
Kailang Yang272a5272007-05-14 11:00:38 +0200101 ALC262_SONY_ASSAMD,
Kailang Yang83c34212007-07-05 11:43:05 +0200102 ALC262_BENQ_T31,
Tobin Davisf651b502007-10-26 12:40:47 +0200103 ALC262_ULTRA,
Jiang zhe0e31daf2008-03-20 12:12:39 +0100104 ALC262_LENOVO_3000,
Pascal Terjane8f9ae22008-08-04 14:36:05 +0200105 ALC262_NEC,
Kailang Yang4e555fe2008-08-26 13:05:55 +0200106 ALC262_TOSHIBA_S06,
Hiroshi Miura9f99a632008-08-28 16:09:06 +0200107 ALC262_TOSHIBA_RX1,
Tony Vroonba340e82009-02-02 19:01:30 +0000108 ALC262_TYAN,
Kailang Yangdf694da2005-12-05 19:42:22 +0100109 ALC262_AUTO,
110 ALC262_MODEL_LAST /* last tag */
111};
112
Kailang Yanga361d842007-06-05 12:30:55 +0200113/* ALC268 models */
114enum {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +0200115 ALC267_QUANTA_IL1,
Kailang Yanga361d842007-06-05 12:30:55 +0200116 ALC268_3ST,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200117 ALC268_TOSHIBA,
Takashi Iwaid2738092007-08-16 14:59:45 +0200118 ALC268_ACER,
Takashi Iwaic238b4f2008-11-05 14:57:20 +0100119 ALC268_ACER_DMIC,
Kailang Yang8ef355d2008-08-26 13:10:22 +0200120 ALC268_ACER_ASPIRE_ONE,
Takashi Iwai3866f0b2008-01-15 12:37:42 +0100121 ALC268_DELL,
Mirco Tischlerf12462c2008-02-04 12:33:59 +0100122 ALC268_ZEPTO,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +0100123#ifdef CONFIG_SND_DEBUG
124 ALC268_TEST,
125#endif
Kailang Yanga361d842007-06-05 12:30:55 +0200126 ALC268_AUTO,
127 ALC268_MODEL_LAST /* last tag */
128};
129
Kailang Yangf6a92242007-12-13 16:52:54 +0100130/* ALC269 models */
131enum {
132 ALC269_BASIC,
Kailang Yang60db6b52008-08-26 13:13:00 +0200133 ALC269_QUANTA_FL1,
Kailang 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,
Kailang Yang272a5272007-05-14 11:00:38 +0200211 ALC882_AUTO,
Kailang Yangdf694da2005-12-05 19:42:22 +0100212 ALC882_MODEL_LAST,
213};
214
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200215/* ALC883 models */
216enum {
217 ALC883_3ST_2ch_DIG,
218 ALC883_3ST_6ch_DIG,
219 ALC883_3ST_6ch,
220 ALC883_6ST_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +0200221 ALC883_TARGA_DIG,
222 ALC883_TARGA_2ch_DIG,
Vladimir Avdoninbab282b92006-08-22 13:31:58 +0200223 ALC883_ACER,
Tobin Davis2880a862007-08-07 11:50:26 +0200224 ALC883_ACER_ASPIRE,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +0800225 ALC888_ACER_ASPIRE_4930G,
Hector Martin3b315d72009-06-02 10:54:19 +0200226 ALC888_ACER_ASPIRE_8930G,
Tobin Davisc07584c2006-10-13 12:32:16 +0200227 ALC883_MEDION,
Kailang Yangea1fb292008-08-26 12:58:38 +0200228 ALC883_MEDION_MD2,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +0100229 ALC883_LAPTOP_EAPD,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200230 ALC883_LENOVO_101E_2ch,
Kailang Yang272a5272007-05-14 11:00:38 +0200231 ALC883_LENOVO_NB0763,
Kailang Yang189609a2007-08-20 11:31:23 +0200232 ALC888_LENOVO_MS7195_DIG,
Kailang Yange2757d52008-08-26 13:17:46 +0200233 ALC888_LENOVO_SKY,
Kailang Yangea1fb292008-08-26 12:58:38 +0200234 ALC883_HAIER_W66,
Claudio Matsuoka4723c022007-07-13 14:36:19 +0200235 ALC888_3ST_HP,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +0100236 ALC888_6ST_DELL,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +0100237 ALC883_MITAC,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +0100238 ALC883_CLEVO_M720,
Jiang zhefb97dc62008-03-06 11:07:11 +0100239 ALC883_FUJITSU_PI2515,
Vincent Petryef8ef5f2008-11-23 11:31:41 +0800240 ALC888_FUJITSU_XA3530,
Jiang zhe17bba1b2008-06-04 12:11:07 +0200241 ALC883_3ST_6ch_INTEL,
Kailang Yange2757d52008-08-26 13:17:46 +0200242 ALC888_ASUS_M90V,
243 ALC888_ASUS_EEE1601,
Torben Schulzeb4c41d2009-05-18 15:02:35 +0200244 ALC889A_MB31,
Wu Fengguang3ab90932008-11-17 09:51:09 +0100245 ALC1200_ASUS_P5Q,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200246 ALC883_AUTO,
247 ALC883_MODEL_LAST,
248};
249
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200250/* styles of capture selection */
251enum {
252 CAPT_MUX = 0, /* only mux based */
253 CAPT_MIX, /* only mixer based */
254 CAPT_1MUX_MIX, /* first mux and other mixers */
255};
256
Kailang Yangdf694da2005-12-05 19:42:22 +0100257/* for GPIO Poll */
258#define GPIO_MASK 0x03
259
Takashi Iwai4a79ba342009-04-22 16:31:35 +0200260/* extra amp-initialization sequence types */
261enum {
262 ALC_INIT_NONE,
263 ALC_INIT_DEFAULT,
264 ALC_INIT_GPIO1,
265 ALC_INIT_GPIO2,
266 ALC_INIT_GPIO3,
267};
268
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269struct alc_spec {
270 /* codec parameterization */
Kailang Yangdf694da2005-12-05 19:42:22 +0100271 struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 unsigned int num_mixers;
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100273 struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Takashi Iwai45bdd1c2009-02-06 16:11:25 +0100274 unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275
Kailang Yangdf694da2005-12-05 19:42:22 +0100276 const struct hda_verb *init_verbs[5]; /* initialization verbs
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200277 * don't forget NULL
278 * termination!
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200279 */
280 unsigned int num_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
Takashi Iwai812a2cc2009-05-16 10:00:49 +0200282 char stream_name_analog[16]; /* analog PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 struct hda_pcm_stream *stream_analog_playback;
284 struct hda_pcm_stream *stream_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +0100285 struct hda_pcm_stream *stream_analog_alt_playback;
286 struct hda_pcm_stream *stream_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
Takashi Iwai812a2cc2009-05-16 10:00:49 +0200288 char stream_name_digital[16]; /* digital PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 struct hda_pcm_stream *stream_digital_playback;
290 struct hda_pcm_stream *stream_digital_capture;
291
292 /* playback */
Takashi Iwai16ded522005-06-10 19:58:24 +0200293 struct hda_multi_out multiout; /* playback set-up
294 * max_channels, dacs must be set
295 * dig_out_nid and hp_nid are optional
296 */
Takashi Iwai63300792008-01-24 15:31:36 +0100297 hda_nid_t alt_dac_nid;
Takashi Iwai6a05ac42009-02-13 11:19:09 +0100298 hda_nid_t slave_dig_outs[3]; /* optional - for auto-parsing */
Takashi Iwai8c441982009-01-20 18:30:20 +0100299 int dig_out_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
301 /* capture */
302 unsigned int num_adc_nids;
303 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100304 hda_nid_t *capsrc_nids;
Takashi Iwai16ded522005-06-10 19:58:24 +0200305 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200306 int capture_style; /* capture style (CAPT_*) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
308 /* capture source */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200309 unsigned int num_mux_defs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 const struct hda_input_mux *input_mux;
311 unsigned int cur_mux[3];
312
313 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100314 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 int num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200316 int need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200317 int const_channel_count;
318 int ext_channel_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
320 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100321 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200322
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200323 /* dynamic controls, init_verbs and input_mux */
324 struct auto_pin_cfg autocfg;
Takashi Iwai603c4012008-07-30 15:01:44 +0200325 struct snd_array kctls;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200326 struct hda_input_mux private_imux[3];
Takashi Iwai41923e42007-10-22 17:20:10 +0200327 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai834be882006-03-01 14:16:17 +0100328
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100329 /* hooks */
330 void (*init_hook)(struct hda_codec *codec);
331 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
332
Takashi Iwai834be882006-03-01 14:16:17 +0100333 /* for pin sensing */
334 unsigned int sense_updated: 1;
335 unsigned int jack_present: 1;
Takashi Iwaibec15c32008-01-28 18:16:30 +0100336 unsigned int master_sw: 1;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200337
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100338 /* other flags */
339 unsigned int no_analog :1; /* digital I/O only */
Takashi Iwai4a79ba342009-04-22 16:31:35 +0200340 int init_amp;
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100341
Takashi Iwai2134ea42008-01-10 16:53:55 +0100342 /* for virtual master */
343 hda_nid_t vmaster_nid;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200344#ifdef CONFIG_SND_HDA_POWER_SAVE
345 struct hda_loopback_check loopback;
346#endif
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200347
348 /* for PLL fix */
349 hda_nid_t pll_nid;
350 unsigned int pll_coef_idx, pll_coef_bit;
Kailang Yangdf694da2005-12-05 19:42:22 +0100351};
352
353/*
354 * configuration template - to be copied to the spec instance
355 */
356struct alc_config_preset {
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200357 struct snd_kcontrol_new *mixers[5]; /* should be identical size
358 * with spec
359 */
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100360 struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Kailang Yangdf694da2005-12-05 19:42:22 +0100361 const struct hda_verb *init_verbs[5];
362 unsigned int num_dacs;
363 hda_nid_t *dac_nids;
364 hda_nid_t dig_out_nid; /* optional */
365 hda_nid_t hp_nid; /* optional */
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800366 hda_nid_t *slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100367 unsigned int num_adc_nids;
368 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100369 hda_nid_t *capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100370 hda_nid_t dig_in_nid;
371 unsigned int num_channel_mode;
372 const struct hda_channel_mode *channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200373 int need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200374 int const_channel_count;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200375 unsigned int num_mux_defs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100376 const struct hda_input_mux *input_mux;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100377 void (*unsol_event)(struct hda_codec *, unsigned int);
378 void (*init_hook)(struct hda_codec *);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200379#ifdef CONFIG_SND_HDA_POWER_SAVE
380 struct hda_amp_list *loopbacks;
381#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382};
383
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
385/*
386 * input MUX handling
387 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200388static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
389 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390{
391 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
392 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200393 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
394 if (mux_idx >= spec->num_mux_defs)
395 mux_idx = 0;
396 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397}
398
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200399static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
400 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401{
402 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
403 struct alc_spec *spec = codec->spec;
404 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
405
406 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
407 return 0;
408}
409
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200410static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
411 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412{
413 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
414 struct alc_spec *spec = codec->spec;
Takashi Iwaicd896c32008-11-18 12:36:33 +0100415 const struct hda_input_mux *imux;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwaicd896c32008-11-18 12:36:33 +0100417 unsigned int mux_idx;
Takashi Iwaie1406342008-02-11 18:32:32 +0100418 hda_nid_t nid = spec->capsrc_nids ?
419 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420
Takashi Iwaicd896c32008-11-18 12:36:33 +0100421 mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
422 imux = &spec->input_mux[mux_idx];
423
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200424 if (spec->capture_style &&
425 !(spec->capture_style == CAPT_1MUX_MIX && !adc_idx)) {
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100426 /* Matrix-mixer style (e.g. ALC882) */
427 unsigned int *cur_val = &spec->cur_mux[adc_idx];
428 unsigned int i, idx;
429
430 idx = ucontrol->value.enumerated.item[0];
431 if (idx >= imux->num_items)
432 idx = imux->num_items - 1;
433 if (*cur_val == idx)
434 return 0;
435 for (i = 0; i < imux->num_items; i++) {
436 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
437 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
438 imux->items[i].index,
439 HDA_AMP_MUTE, v);
440 }
441 *cur_val = idx;
442 return 1;
443 } else {
444 /* MUX style (e.g. ALC880) */
Takashi Iwaicd896c32008-11-18 12:36:33 +0100445 return snd_hda_input_mux_put(codec, imux, ucontrol, nid,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100446 &spec->cur_mux[adc_idx]);
447 }
448}
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200449
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450/*
451 * channel mode setting
452 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200453static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
454 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455{
456 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
457 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100458 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
459 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460}
461
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200462static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
463 struct snd_ctl_elem_value *ucontrol)
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_get(codec, ucontrol, spec->channel_mode,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200468 spec->num_channel_mode,
Hector Martin3b315d72009-06-02 10:54:19 +0200469 spec->ext_channel_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470}
471
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200472static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
473 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474{
475 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
476 struct alc_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200477 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
478 spec->num_channel_mode,
Hector Martin3b315d72009-06-02 10:54:19 +0200479 &spec->ext_channel_count);
480 if (err >= 0 && !spec->const_channel_count) {
481 spec->multiout.max_channels = spec->ext_channel_count;
482 if (spec->need_dac_fix)
483 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
484 }
Takashi Iwai4e195a72006-07-28 14:47:34 +0200485 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486}
487
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100489 * Control the mode of pin widget settings via the mixer. "pc" is used
Kailang Yangea1fb292008-08-26 12:58:38 +0200490 * instead of "%" to avoid consequences of accidently treating the % as
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100491 * being part of a format specifier. Maximum allowed length of a value is
492 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100493 *
494 * Note: some retasking pin complexes seem to ignore requests for input
495 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
496 * are requested. Therefore order this list so that this behaviour will not
497 * cause problems when mixer clients move through the enum sequentially.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200498 * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
499 * March 2006.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200500 */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100501static char *alc_pin_mode_names[] = {
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100502 "Mic 50pc bias", "Mic 80pc bias",
503 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100504};
505static unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100506 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100507};
508/* The control can present all 5 options, or it can limit the options based
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200509 * in the pin being assumed to be exclusively an input or an output pin. In
510 * addition, "input" pins may or may not process the mic bias option
511 * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
512 * accept requests for bias as of chip versions up to March 2006) and/or
513 * wiring in the computer.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100514 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200515#define ALC_PIN_DIR_IN 0x00
516#define ALC_PIN_DIR_OUT 0x01
517#define ALC_PIN_DIR_INOUT 0x02
518#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
519#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100520
Kailang Yangea1fb292008-08-26 12:58:38 +0200521/* Info about the pin modes supported by the different pin direction modes.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100522 * For each direction the minimum and maximum values are given.
523 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200524static signed char alc_pin_mode_dir_info[5][2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100525 { 0, 2 }, /* ALC_PIN_DIR_IN */
526 { 3, 4 }, /* ALC_PIN_DIR_OUT */
527 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200528 { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
529 { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100530};
531#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
532#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
533#define alc_pin_mode_n_items(_dir) \
534 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
535
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200536static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
537 struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200538{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100539 unsigned int item_num = uinfo->value.enumerated.item;
540 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
541
542 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200543 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100544 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
545
546 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
547 item_num = alc_pin_mode_min(dir);
548 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200549 return 0;
550}
551
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200552static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
553 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200554{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100555 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200556 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
557 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100558 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200559 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200560 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
561 AC_VERB_GET_PIN_WIDGET_CONTROL,
562 0x00);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200563
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100564 /* Find enumerated value for current pinctl setting */
565 i = alc_pin_mode_min(dir);
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200566 while (alc_pin_mode_values[i] != pinctl && i <= alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100567 i++;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200568 *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100569 return 0;
570}
571
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200572static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
573 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100574{
575 signed int change;
576 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
577 hda_nid_t nid = kcontrol->private_value & 0xffff;
578 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
579 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200580 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
581 AC_VERB_GET_PIN_WIDGET_CONTROL,
582 0x00);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100583
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200584 if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100585 val = alc_pin_mode_min(dir);
586
587 change = pinctl != alc_pin_mode_values[val];
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100588 if (change) {
589 /* Set pin mode to that requested */
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200590 snd_hda_codec_write_cache(codec, nid, 0,
591 AC_VERB_SET_PIN_WIDGET_CONTROL,
592 alc_pin_mode_values[val]);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100593
Kailang Yangea1fb292008-08-26 12:58:38 +0200594 /* Also enable the retasking pin's input/output as required
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100595 * for the requested pin mode. Enum values of 2 or less are
596 * input modes.
597 *
598 * Dynamically switching the input/output buffers probably
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200599 * reduces noise slightly (particularly on input) so we'll
600 * do it. However, having both input and output buffers
601 * enabled simultaneously doesn't seem to be problematic if
602 * this turns out to be necessary in the future.
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100603 */
604 if (val <= 2) {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200605 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
606 HDA_AMP_MUTE, HDA_AMP_MUTE);
607 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
608 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100609 } else {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200610 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
611 HDA_AMP_MUTE, HDA_AMP_MUTE);
612 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
613 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100614 }
615 }
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200616 return change;
617}
618
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100619#define ALC_PIN_MODE(xname, nid, dir) \
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200620 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100621 .info = alc_pin_mode_info, \
622 .get = alc_pin_mode_get, \
623 .put = alc_pin_mode_put, \
624 .private_value = nid | (dir<<16) }
Kailang Yangdf694da2005-12-05 19:42:22 +0100625
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100626/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
627 * together using a mask with more than one bit set. This control is
628 * currently used only by the ALC260 test model. At this stage they are not
629 * needed for any "production" models.
630 */
631#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200632#define alc_gpio_data_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200633
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200634static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
635 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100636{
637 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
638 hda_nid_t nid = kcontrol->private_value & 0xffff;
639 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
640 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200641 unsigned int val = snd_hda_codec_read(codec, nid, 0,
642 AC_VERB_GET_GPIO_DATA, 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100643
644 *valp = (val & mask) != 0;
645 return 0;
646}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200647static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
648 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100649{
650 signed int change;
651 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
652 hda_nid_t nid = kcontrol->private_value & 0xffff;
653 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
654 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200655 unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
656 AC_VERB_GET_GPIO_DATA,
657 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100658
659 /* Set/unset the masked GPIO bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200660 change = (val == 0 ? 0 : mask) != (gpio_data & mask);
661 if (val == 0)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100662 gpio_data &= ~mask;
663 else
664 gpio_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200665 snd_hda_codec_write_cache(codec, nid, 0,
666 AC_VERB_SET_GPIO_DATA, gpio_data);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100667
668 return change;
669}
670#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
671 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
672 .info = alc_gpio_data_info, \
673 .get = alc_gpio_data_get, \
674 .put = alc_gpio_data_put, \
675 .private_value = nid | (mask<<16) }
676#endif /* CONFIG_SND_DEBUG */
677
Jonathan Woithe92621f12006-02-28 11:47:47 +0100678/* A switch control to allow the enabling of the digital IO pins on the
679 * ALC260. This is incredibly simplistic; the intention of this control is
680 * to provide something in the test model allowing digital outputs to be
681 * identified if present. If models are found which can utilise these
682 * outputs a more complete mixer control can be devised for those models if
683 * necessary.
684 */
685#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200686#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200687
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200688static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
689 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100690{
691 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
692 hda_nid_t nid = kcontrol->private_value & 0xffff;
693 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
694 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200695 unsigned int val = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100696 AC_VERB_GET_DIGI_CONVERT_1, 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100697
698 *valp = (val & mask) != 0;
699 return 0;
700}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200701static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
702 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100703{
704 signed int change;
705 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
706 hda_nid_t nid = kcontrol->private_value & 0xffff;
707 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
708 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200709 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100710 AC_VERB_GET_DIGI_CONVERT_1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200711 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100712
713 /* Set/unset the masked control bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200714 change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100715 if (val==0)
716 ctrl_data &= ~mask;
717 else
718 ctrl_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200719 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
720 ctrl_data);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100721
722 return change;
723}
724#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
725 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
726 .info = alc_spdif_ctrl_info, \
727 .get = alc_spdif_ctrl_get, \
728 .put = alc_spdif_ctrl_put, \
729 .private_value = nid | (mask<<16) }
730#endif /* CONFIG_SND_DEBUG */
731
Jonathan Woithef8225f62008-01-08 12:16:54 +0100732/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
733 * Again, this is only used in the ALC26x test models to help identify when
734 * the EAPD line must be asserted for features to work.
735 */
736#ifdef CONFIG_SND_DEBUG
737#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
738
739static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
740 struct snd_ctl_elem_value *ucontrol)
741{
742 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
743 hda_nid_t nid = kcontrol->private_value & 0xffff;
744 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
745 long *valp = ucontrol->value.integer.value;
746 unsigned int val = snd_hda_codec_read(codec, nid, 0,
747 AC_VERB_GET_EAPD_BTLENABLE, 0x00);
748
749 *valp = (val & mask) != 0;
750 return 0;
751}
752
753static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
754 struct snd_ctl_elem_value *ucontrol)
755{
756 int change;
757 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
758 hda_nid_t nid = kcontrol->private_value & 0xffff;
759 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
760 long val = *ucontrol->value.integer.value;
761 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
762 AC_VERB_GET_EAPD_BTLENABLE,
763 0x00);
764
765 /* Set/unset the masked control bit(s) as needed */
766 change = (!val ? 0 : mask) != (ctrl_data & mask);
767 if (!val)
768 ctrl_data &= ~mask;
769 else
770 ctrl_data |= mask;
771 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
772 ctrl_data);
773
774 return change;
775}
776
777#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
778 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
779 .info = alc_eapd_ctrl_info, \
780 .get = alc_eapd_ctrl_get, \
781 .put = alc_eapd_ctrl_put, \
782 .private_value = nid | (mask<<16) }
783#endif /* CONFIG_SND_DEBUG */
784
Kailang Yangdf694da2005-12-05 19:42:22 +0100785/*
Takashi Iwai23f0c042009-02-26 13:03:58 +0100786 * set up the input pin config (depending on the given auto-pin type)
787 */
788static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
789 int auto_pin_type)
790{
791 unsigned int val = PIN_IN;
792
793 if (auto_pin_type <= AUTO_PIN_FRONT_MIC) {
794 unsigned int pincap;
Takashi Iwai1327a322009-03-23 13:07:47 +0100795 pincap = snd_hda_query_pin_caps(codec, nid);
Takashi Iwai23f0c042009-02-26 13:03:58 +0100796 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
797 if (pincap & AC_PINCAP_VREF_80)
798 val = PIN_VREF80;
Takashi Iwai461c6c32009-05-25 08:06:02 +0200799 else if (pincap & AC_PINCAP_VREF_50)
800 val = PIN_VREF50;
801 else if (pincap & AC_PINCAP_VREF_100)
802 val = PIN_VREF100;
803 else if (pincap & AC_PINCAP_VREF_GRD)
804 val = PIN_VREFGRD;
Takashi Iwai23f0c042009-02-26 13:03:58 +0100805 }
806 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
807}
808
809/*
Takashi Iwaid88897e2008-10-31 15:01:37 +0100810 */
811static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix)
812{
813 if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
814 return;
815 spec->mixers[spec->num_mixers++] = mix;
816}
817
818static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
819{
820 if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
821 return;
822 spec->init_verbs[spec->num_init_verbs++] = verb;
823}
824
Takashi Iwaidaead532008-11-28 12:55:36 +0100825#ifdef CONFIG_PROC_FS
826/*
827 * hook for proc
828 */
829static void print_realtek_coef(struct snd_info_buffer *buffer,
830 struct hda_codec *codec, hda_nid_t nid)
831{
832 int coeff;
833
834 if (nid != 0x20)
835 return;
836 coeff = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0);
837 snd_iprintf(buffer, " Processing Coefficient: 0x%02x\n", coeff);
838 coeff = snd_hda_codec_read(codec, nid, 0,
839 AC_VERB_GET_COEF_INDEX, 0);
840 snd_iprintf(buffer, " Coefficient Index: 0x%02x\n", coeff);
841}
842#else
843#define print_realtek_coef NULL
844#endif
845
Takashi Iwaid88897e2008-10-31 15:01:37 +0100846/*
Kailang Yangdf694da2005-12-05 19:42:22 +0100847 * set up from the preset table
848 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200849static void setup_preset(struct alc_spec *spec,
850 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100851{
852 int i;
853
854 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100855 add_mixer(spec, preset->mixers[i]);
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100856 spec->cap_mixer = preset->cap_mixer;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200857 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
858 i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100859 add_verb(spec, preset->init_verbs[i]);
Kailang Yangea1fb292008-08-26 12:58:38 +0200860
Kailang Yangdf694da2005-12-05 19:42:22 +0100861 spec->channel_mode = preset->channel_mode;
862 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200863 spec->need_dac_fix = preset->need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200864 spec->const_channel_count = preset->const_channel_count;
Kailang Yangdf694da2005-12-05 19:42:22 +0100865
Hector Martin3b315d72009-06-02 10:54:19 +0200866 if (preset->const_channel_count)
867 spec->multiout.max_channels = preset->const_channel_count;
868 else
869 spec->multiout.max_channels = spec->channel_mode[0].channels;
870 spec->ext_channel_count = spec->channel_mode[0].channels;
Kailang Yangdf694da2005-12-05 19:42:22 +0100871
872 spec->multiout.num_dacs = preset->num_dacs;
873 spec->multiout.dac_nids = preset->dac_nids;
874 spec->multiout.dig_out_nid = preset->dig_out_nid;
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800875 spec->multiout.slave_dig_outs = preset->slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100876 spec->multiout.hp_nid = preset->hp_nid;
Kailang Yangea1fb292008-08-26 12:58:38 +0200877
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200878 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200879 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200880 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100881 spec->input_mux = preset->input_mux;
882
883 spec->num_adc_nids = preset->num_adc_nids;
884 spec->adc_nids = preset->adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100885 spec->capsrc_nids = preset->capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100886 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100887
888 spec->unsol_event = preset->unsol_event;
889 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200890#ifdef CONFIG_SND_HDA_POWER_SAVE
891 spec->loopback.amplist = preset->loopbacks;
892#endif
Kailang Yangdf694da2005-12-05 19:42:22 +0100893}
894
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200895/* Enable GPIO mask and set output */
896static struct hda_verb alc_gpio1_init_verbs[] = {
897 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
898 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
899 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
900 { }
901};
902
903static struct hda_verb alc_gpio2_init_verbs[] = {
904 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
905 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
906 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
907 { }
908};
909
Kailang Yangbdd148a2007-05-08 15:19:08 +0200910static struct hda_verb alc_gpio3_init_verbs[] = {
911 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
912 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
913 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
914 { }
915};
916
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200917/*
918 * Fix hardware PLL issue
919 * On some codecs, the analog PLL gating control must be off while
920 * the default value is 1.
921 */
922static void alc_fix_pll(struct hda_codec *codec)
923{
924 struct alc_spec *spec = codec->spec;
925 unsigned int val;
926
927 if (!spec->pll_nid)
928 return;
929 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
930 spec->pll_coef_idx);
931 val = snd_hda_codec_read(codec, spec->pll_nid, 0,
932 AC_VERB_GET_PROC_COEF, 0);
933 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
934 spec->pll_coef_idx);
935 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
936 val & ~(1 << spec->pll_coef_bit));
937}
938
939static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
940 unsigned int coef_idx, unsigned int coef_bit)
941{
942 struct alc_spec *spec = codec->spec;
943 spec->pll_nid = nid;
944 spec->pll_coef_idx = coef_idx;
945 spec->pll_coef_bit = coef_bit;
946 alc_fix_pll(codec);
947}
948
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200949static void alc_automute_pin(struct hda_codec *codec)
Kailang Yangc9b58002007-10-16 14:30:01 +0200950{
951 struct alc_spec *spec = codec->spec;
Kailang Yangc9b58002007-10-16 14:30:01 +0200952 unsigned int present;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200953 unsigned int nid = spec->autocfg.hp_pins[0];
954 int i;
Kailang Yangc9b58002007-10-16 14:30:01 +0200955
956 /* need to execute and sync at first */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200957 snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0);
958 present = snd_hda_codec_read(codec, nid, 0,
Kailang Yangc9b58002007-10-16 14:30:01 +0200959 AC_VERB_GET_PIN_SENSE, 0);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200960 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
961 for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
962 nid = spec->autocfg.speaker_pins[i];
963 if (!nid)
964 break;
965 snd_hda_codec_write(codec, nid, 0,
966 AC_VERB_SET_PIN_WIDGET_CONTROL,
967 spec->jack_present ? 0 : PIN_OUT);
968 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200969}
970
Takashi Iwai4605b712008-10-31 14:18:24 +0100971#if 0 /* it's broken in some acses -- temporarily disabled */
Kailang Yang7fb0d782008-10-15 11:12:35 +0200972static void alc_mic_automute(struct hda_codec *codec)
973{
974 struct alc_spec *spec = codec->spec;
975 unsigned int present;
976 unsigned int mic_nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
977 unsigned int fmic_nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
978 unsigned int mix_nid = spec->capsrc_nids[0];
979 unsigned int capsrc_idx_mic, capsrc_idx_fmic;
980
981 capsrc_idx_mic = mic_nid - 0x18;
982 capsrc_idx_fmic = fmic_nid - 0x18;
983 present = snd_hda_codec_read(codec, mic_nid, 0,
984 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
985 snd_hda_codec_write(codec, mix_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
986 0x7000 | (capsrc_idx_mic << 8) | (present ? 0 : 0x80));
987 snd_hda_codec_write(codec, mix_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
988 0x7000 | (capsrc_idx_fmic << 8) | (present ? 0x80 : 0));
989 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, capsrc_idx_fmic,
990 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
991}
Takashi Iwai4605b712008-10-31 14:18:24 +0100992#else
Takashi Iwai45bdd1c2009-02-06 16:11:25 +0100993#define alc_mic_automute(codec) do {} while(0) /* NOP */
Takashi Iwai4605b712008-10-31 14:18:24 +0100994#endif /* disabled */
Kailang Yang7fb0d782008-10-15 11:12:35 +0200995
Kailang Yangc9b58002007-10-16 14:30:01 +0200996/* unsolicited event for HP jack sensing */
997static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
998{
999 if (codec->vendor_id == 0x10ec0880)
1000 res >>= 28;
1001 else
1002 res >>= 26;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001003 switch (res) {
1004 case ALC880_HP_EVENT:
1005 alc_automute_pin(codec);
1006 break;
1007 case ALC880_MIC_EVENT:
Kailang Yang7fb0d782008-10-15 11:12:35 +02001008 alc_mic_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001009 break;
1010 }
Kailang Yang7fb0d782008-10-15 11:12:35 +02001011}
1012
1013static void alc_inithook(struct hda_codec *codec)
1014{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001015 alc_automute_pin(codec);
Kailang Yang7fb0d782008-10-15 11:12:35 +02001016 alc_mic_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +02001017}
1018
Kailang Yangf9423e72008-05-27 12:32:25 +02001019/* additional initialization for ALC888 variants */
1020static void alc888_coef_init(struct hda_codec *codec)
1021{
1022 unsigned int tmp;
1023
1024 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
1025 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
1026 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
Takashi Iwai37db6232009-03-05 09:40:16 +01001027 if ((tmp & 0xf0) == 0x20)
Kailang Yangf9423e72008-05-27 12:32:25 +02001028 /* alc888S-VC */
1029 snd_hda_codec_read(codec, 0x20, 0,
1030 AC_VERB_SET_PROC_COEF, 0x830);
1031 else
1032 /* alc888-VB */
1033 snd_hda_codec_read(codec, 0x20, 0,
1034 AC_VERB_SET_PROC_COEF, 0x3030);
1035}
1036
Takashi Iwai4a79ba342009-04-22 16:31:35 +02001037static void alc_auto_init_amp(struct hda_codec *codec, int type)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001038{
Takashi Iwai4a79ba342009-04-22 16:31:35 +02001039 unsigned int tmp;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001040
Takashi Iwai4a79ba342009-04-22 16:31:35 +02001041 switch (type) {
1042 case ALC_INIT_GPIO1:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001043 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
1044 break;
Takashi Iwai4a79ba342009-04-22 16:31:35 +02001045 case ALC_INIT_GPIO2:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001046 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
1047 break;
Takashi Iwai4a79ba342009-04-22 16:31:35 +02001048 case ALC_INIT_GPIO3:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001049 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
1050 break;
Takashi Iwai4a79ba342009-04-22 16:31:35 +02001051 case ALC_INIT_DEFAULT:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001052 switch (codec->vendor_id) {
Kailang Yangc9b58002007-10-16 14:30:01 +02001053 case 0x10ec0260:
1054 snd_hda_codec_write(codec, 0x0f, 0,
1055 AC_VERB_SET_EAPD_BTLENABLE, 2);
1056 snd_hda_codec_write(codec, 0x10, 0,
1057 AC_VERB_SET_EAPD_BTLENABLE, 2);
1058 break;
1059 case 0x10ec0262:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001060 case 0x10ec0267:
1061 case 0x10ec0268:
Kailang Yangc9b58002007-10-16 14:30:01 +02001062 case 0x10ec0269:
Takashi Iwaic6e8f2d2009-02-06 12:45:52 +01001063 case 0x10ec0272:
Kailang Yangf9423e72008-05-27 12:32:25 +02001064 case 0x10ec0660:
1065 case 0x10ec0662:
1066 case 0x10ec0663:
Kailang Yangc9b58002007-10-16 14:30:01 +02001067 case 0x10ec0862:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001068 case 0x10ec0889:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001069 snd_hda_codec_write(codec, 0x14, 0,
1070 AC_VERB_SET_EAPD_BTLENABLE, 2);
1071 snd_hda_codec_write(codec, 0x15, 0,
1072 AC_VERB_SET_EAPD_BTLENABLE, 2);
Kailang Yangc9b58002007-10-16 14:30:01 +02001073 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +02001074 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001075 switch (codec->vendor_id) {
1076 case 0x10ec0260:
1077 snd_hda_codec_write(codec, 0x1a, 0,
1078 AC_VERB_SET_COEF_INDEX, 7);
1079 tmp = snd_hda_codec_read(codec, 0x1a, 0,
1080 AC_VERB_GET_PROC_COEF, 0);
1081 snd_hda_codec_write(codec, 0x1a, 0,
1082 AC_VERB_SET_COEF_INDEX, 7);
1083 snd_hda_codec_write(codec, 0x1a, 0,
1084 AC_VERB_SET_PROC_COEF,
1085 tmp | 0x2010);
1086 break;
1087 case 0x10ec0262:
1088 case 0x10ec0880:
1089 case 0x10ec0882:
1090 case 0x10ec0883:
1091 case 0x10ec0885:
Takashi Iwai4a5a4c52009-02-06 12:46:59 +01001092 case 0x10ec0887:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001093 case 0x10ec0889:
Kailang Yangc9b58002007-10-16 14:30:01 +02001094 snd_hda_codec_write(codec, 0x20, 0,
1095 AC_VERB_SET_COEF_INDEX, 7);
1096 tmp = snd_hda_codec_read(codec, 0x20, 0,
1097 AC_VERB_GET_PROC_COEF, 0);
1098 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001099 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001100 snd_hda_codec_write(codec, 0x20, 0,
1101 AC_VERB_SET_PROC_COEF,
1102 tmp | 0x2010);
1103 break;
Kailang Yangf9423e72008-05-27 12:32:25 +02001104 case 0x10ec0888:
Takashi Iwai4a79ba342009-04-22 16:31:35 +02001105 alc888_coef_init(codec);
Kailang Yangf9423e72008-05-27 12:32:25 +02001106 break;
Kailang Yangc9b58002007-10-16 14:30:01 +02001107 case 0x10ec0267:
1108 case 0x10ec0268:
1109 snd_hda_codec_write(codec, 0x20, 0,
1110 AC_VERB_SET_COEF_INDEX, 7);
1111 tmp = snd_hda_codec_read(codec, 0x20, 0,
1112 AC_VERB_GET_PROC_COEF, 0);
1113 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001114 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001115 snd_hda_codec_write(codec, 0x20, 0,
1116 AC_VERB_SET_PROC_COEF,
1117 tmp | 0x3000);
1118 break;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001119 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001120 break;
1121 }
Takashi Iwai4a79ba342009-04-22 16:31:35 +02001122}
Kailang Yangea1fb292008-08-26 12:58:38 +02001123
Takashi Iwai4a79ba342009-04-22 16:31:35 +02001124static void alc_init_auto_hp(struct hda_codec *codec)
1125{
1126 struct alc_spec *spec = codec->spec;
1127
1128 if (!spec->autocfg.hp_pins[0])
Kailang Yangc9b58002007-10-16 14:30:01 +02001129 return;
Takashi Iwai4a79ba342009-04-22 16:31:35 +02001130
Kailang Yangc9b58002007-10-16 14:30:01 +02001131 if (!spec->autocfg.speaker_pins[0]) {
Takashi Iwai2a2ed0d2009-04-28 13:01:26 +02001132 if (spec->autocfg.line_out_pins[0] &&
1133 spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
Kailang Yangc9b58002007-10-16 14:30:01 +02001134 spec->autocfg.speaker_pins[0] =
Kailang Yang8c427222008-01-10 13:03:59 +01001135 spec->autocfg.line_out_pins[0];
Kailang Yangc9b58002007-10-16 14:30:01 +02001136 else
1137 return;
1138 }
1139
Takashi Iwai2a2ed0d2009-04-28 13:01:26 +02001140 snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
1141 spec->autocfg.hp_pins[0]);
Takashi Iwai4a79ba342009-04-22 16:31:35 +02001142 snd_hda_codec_write_cache(codec, spec->autocfg.hp_pins[0], 0,
1143 AC_VERB_SET_UNSOLICITED_ENABLE,
1144 AC_USRSP_EN | ALC880_HP_EVENT);
1145 spec->unsol_event = alc_sku_unsol_event;
1146}
1147
1148/* check subsystem ID and set up device-specific initialization;
1149 * return 1 if initialized, 0 if invalid SSID
1150 */
1151/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
1152 * 31 ~ 16 : Manufacture ID
1153 * 15 ~ 8 : SKU ID
1154 * 7 ~ 0 : Assembly ID
1155 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
1156 */
1157static int alc_subsystem_id(struct hda_codec *codec,
1158 hda_nid_t porta, hda_nid_t porte,
1159 hda_nid_t portd)
1160{
1161 unsigned int ass, tmp, i;
1162 unsigned nid;
1163 struct alc_spec *spec = codec->spec;
1164
1165 ass = codec->subsystem_id & 0xffff;
1166 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
1167 goto do_sku;
1168
1169 /* invalid SSID, check the special NID pin defcfg instead */
1170 /*
1171 * 31~30 : port conetcivity
1172 * 29~21 : reserve
1173 * 20 : PCBEEP input
1174 * 19~16 : Check sum (15:1)
1175 * 15~1 : Custom
1176 * 0 : override
1177 */
1178 nid = 0x1d;
1179 if (codec->vendor_id == 0x10ec0260)
1180 nid = 0x17;
1181 ass = snd_hda_codec_get_pincfg(codec, nid);
1182 snd_printd("realtek: No valid SSID, "
1183 "checking pincfg 0x%08x for NID 0x%x\n",
Takashi Iwaicb6605c2009-04-28 13:03:19 +02001184 ass, nid);
Takashi Iwai4a79ba342009-04-22 16:31:35 +02001185 if (!(ass & 1) && !(ass & 0x100000))
1186 return 0;
1187 if ((ass >> 30) != 1) /* no physical connection */
1188 return 0;
1189
1190 /* check sum */
1191 tmp = 0;
1192 for (i = 1; i < 16; i++) {
1193 if ((ass >> i) & 1)
1194 tmp++;
1195 }
1196 if (((ass >> 16) & 0xf) != tmp)
1197 return 0;
1198do_sku:
1199 snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
1200 ass & 0xffff, codec->vendor_id);
1201 /*
1202 * 0 : override
1203 * 1 : Swap Jack
1204 * 2 : 0 --> Desktop, 1 --> Laptop
1205 * 3~5 : External Amplifier control
1206 * 7~6 : Reserved
1207 */
1208 tmp = (ass & 0x38) >> 3; /* external Amp control */
1209 switch (tmp) {
1210 case 1:
1211 spec->init_amp = ALC_INIT_GPIO1;
1212 break;
1213 case 3:
1214 spec->init_amp = ALC_INIT_GPIO2;
1215 break;
1216 case 7:
1217 spec->init_amp = ALC_INIT_GPIO3;
1218 break;
1219 case 5:
1220 spec->init_amp = ALC_INIT_DEFAULT;
1221 break;
1222 }
1223
1224 /* is laptop or Desktop and enable the function "Mute internal speaker
1225 * when the external headphone out jack is plugged"
1226 */
1227 if (!(ass & 0x8000))
1228 return 1;
1229 /*
1230 * 10~8 : Jack location
1231 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
1232 * 14~13: Resvered
1233 * 15 : 1 --> enable the function "Mute internal speaker
1234 * when the external headphone out jack is plugged"
1235 */
Kailang Yangc9b58002007-10-16 14:30:01 +02001236 if (!spec->autocfg.hp_pins[0]) {
1237 tmp = (ass >> 11) & 0x3; /* HP to chassis */
1238 if (tmp == 0)
1239 spec->autocfg.hp_pins[0] = porta;
1240 else if (tmp == 1)
1241 spec->autocfg.hp_pins[0] = porte;
1242 else if (tmp == 2)
1243 spec->autocfg.hp_pins[0] = portd;
1244 else
Takashi Iwai4a79ba342009-04-22 16:31:35 +02001245 return 1;
Kailang Yangc9b58002007-10-16 14:30:01 +02001246 }
1247
Takashi Iwai4a79ba342009-04-22 16:31:35 +02001248 alc_init_auto_hp(codec);
1249 return 1;
1250}
Kailang Yangea1fb292008-08-26 12:58:38 +02001251
Takashi Iwai4a79ba342009-04-22 16:31:35 +02001252static void alc_ssid_check(struct hda_codec *codec,
1253 hda_nid_t porta, hda_nid_t porte, hda_nid_t portd)
1254{
1255 if (!alc_subsystem_id(codec, porta, porte, portd)) {
1256 struct alc_spec *spec = codec->spec;
1257 snd_printd("realtek: "
1258 "Enable default setup for auto mode as fallback\n");
1259 spec->init_amp = ALC_INIT_DEFAULT;
1260 alc_init_auto_hp(codec);
1261 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001262}
1263
Takashi Iwai41e41f12005-06-08 14:48:49 +02001264/*
Takashi Iwaif95474e2007-07-10 00:47:43 +02001265 * Fix-up pin default configurations
1266 */
1267
1268struct alc_pincfg {
1269 hda_nid_t nid;
1270 u32 val;
1271};
1272
1273static void alc_fix_pincfg(struct hda_codec *codec,
1274 const struct snd_pci_quirk *quirk,
1275 const struct alc_pincfg **pinfix)
1276{
1277 const struct alc_pincfg *cfg;
1278
1279 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
1280 if (!quirk)
1281 return;
1282
1283 cfg = pinfix[quirk->value];
Takashi Iwai0e8a21b2009-02-20 14:13:06 +01001284 for (; cfg->nid; cfg++)
1285 snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
Takashi Iwaif95474e2007-07-10 00:47:43 +02001286}
1287
1288/*
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001289 * ALC888
1290 */
1291
1292/*
1293 * 2ch mode
1294 */
1295static struct hda_verb alc888_4ST_ch2_intel_init[] = {
1296/* Mic-in jack as mic in */
1297 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1298 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1299/* Line-in jack as Line in */
1300 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1301 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1302/* Line-Out as Front */
1303 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
1304 { } /* end */
1305};
1306
1307/*
1308 * 4ch mode
1309 */
1310static struct hda_verb alc888_4ST_ch4_intel_init[] = {
1311/* Mic-in jack as mic in */
1312 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1313 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1314/* Line-in jack as Surround */
1315 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1316 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1317/* Line-Out as Front */
1318 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
1319 { } /* end */
1320};
1321
1322/*
1323 * 6ch mode
1324 */
1325static struct hda_verb alc888_4ST_ch6_intel_init[] = {
1326/* Mic-in jack as CLFE */
1327 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1328 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1329/* Line-in jack as Surround */
1330 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1331 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1332/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */
1333 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1334 { } /* end */
1335};
1336
1337/*
1338 * 8ch mode
1339 */
1340static struct hda_verb alc888_4ST_ch8_intel_init[] = {
1341/* Mic-in jack as CLFE */
1342 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1343 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1344/* Line-in jack as Surround */
1345 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1346 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1347/* Line-Out as Side */
1348 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1349 { } /* end */
1350};
1351
1352static struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
1353 { 2, alc888_4ST_ch2_intel_init },
1354 { 4, alc888_4ST_ch4_intel_init },
1355 { 6, alc888_4ST_ch6_intel_init },
1356 { 8, alc888_4ST_ch8_intel_init },
1357};
1358
1359/*
1360 * ALC888 Fujitsu Siemens Amillo xa3530
1361 */
1362
1363static struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
1364/* Front Mic: set to PIN_IN (empty by default) */
1365 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1366/* Connect Internal HP to Front */
1367 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1368 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1369 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1370/* Connect Bass HP to Front */
1371 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1372 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1373 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1374/* Connect Line-Out side jack (SPDIF) to Side */
1375 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1376 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1377 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1378/* Connect Mic jack to CLFE */
1379 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1380 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1381 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
1382/* Connect Line-in jack to Surround */
1383 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1384 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1385 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
1386/* Connect HP out jack to Front */
1387 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1388 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1389 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
1390/* Enable unsolicited event for HP jack and Line-out jack */
1391 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1392 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1393 {}
1394};
1395
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001396static void alc_automute_amp(struct hda_codec *codec)
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001397{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001398 struct alc_spec *spec = codec->spec;
1399 unsigned int val, mute;
1400 hda_nid_t nid;
1401 int i;
1402
1403 spec->jack_present = 0;
1404 for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
1405 nid = spec->autocfg.hp_pins[i];
1406 if (!nid)
1407 break;
1408 val = snd_hda_codec_read(codec, nid, 0,
1409 AC_VERB_GET_PIN_SENSE, 0);
1410 if (val & AC_PINSENSE_PRESENCE) {
1411 spec->jack_present = 1;
1412 break;
1413 }
1414 }
1415
1416 mute = spec->jack_present ? HDA_AMP_MUTE : 0;
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001417 /* Toggle internal speakers muting */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001418 for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
1419 nid = spec->autocfg.speaker_pins[i];
1420 if (!nid)
1421 break;
1422 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
1423 HDA_AMP_MUTE, mute);
1424 }
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001425}
1426
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001427static void alc_automute_amp_unsol_event(struct hda_codec *codec,
1428 unsigned int res)
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001429{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001430 if (codec->vendor_id == 0x10ec0880)
1431 res >>= 28;
1432 else
1433 res >>= 26;
1434 if (res == ALC880_HP_EVENT)
1435 alc_automute_amp(codec);
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001436}
1437
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001438static void alc888_fujitsu_xa3530_init_hook(struct hda_codec *codec)
1439{
1440 struct alc_spec *spec = codec->spec;
1441
1442 spec->autocfg.hp_pins[0] = 0x17; /* line-out */
1443 spec->autocfg.hp_pins[1] = 0x1b; /* hp */
1444 spec->autocfg.speaker_pins[0] = 0x14; /* speaker */
1445 spec->autocfg.speaker_pins[1] = 0x15; /* bass */
1446 alc_automute_amp(codec);
1447}
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001448
1449/*
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001450 * ALC888 Acer Aspire 4930G model
1451 */
1452
1453static struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
1454/* Front Mic: set to PIN_IN (empty by default) */
1455 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1456/* Unselect Front Mic by default in input mixer 3 */
1457 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001458/* Enable unsolicited event for HP jack */
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001459 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1460/* Connect Internal HP to front */
1461 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1462 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1463 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1464/* Connect HP out to front */
1465 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1466 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1467 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1468 { }
1469};
1470
Hector Martin3b315d72009-06-02 10:54:19 +02001471/*
Hector Martin018df412009-06-04 00:13:40 +02001472 * ALC889 Acer Aspire 8930G model
Hector Martin3b315d72009-06-02 10:54:19 +02001473 */
1474
Hector Martin018df412009-06-04 00:13:40 +02001475static struct hda_verb alc889_acer_aspire_8930g_verbs[] = {
Hector Martin3b315d72009-06-02 10:54:19 +02001476/* Front Mic: set to PIN_IN (empty by default) */
1477 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1478/* Unselect Front Mic by default in input mixer 3 */
1479 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
1480/* Enable unsolicited event for HP jack */
1481 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1482/* Connect Internal Front to Front */
1483 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1484 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1485 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1486/* Connect Internal Rear to Rear */
1487 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1488 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1489 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
1490/* Connect Internal CLFE to CLFE */
1491 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1492 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1493 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
1494/* Connect HP out to Front */
Hector Martin018df412009-06-04 00:13:40 +02001495 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
Hector Martin3b315d72009-06-02 10:54:19 +02001496 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1497 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1498/* Enable all DACs */
1499/* DAC DISABLE/MUTE 1? */
1500/* setting bits 1-5 disables DAC nids 0x02-0x06 apparently. Init=0x38 */
1501 {0x20, AC_VERB_SET_COEF_INDEX, 0x03},
1502 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
1503/* DAC DISABLE/MUTE 2? */
1504/* some bit here disables the other DACs. Init=0x4900 */
1505 {0x20, AC_VERB_SET_COEF_INDEX, 0x08},
1506 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
1507/* Enable amplifiers */
1508 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
1509 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
Hector Martin018df412009-06-04 00:13:40 +02001510/* DMIC fix
1511 * This laptop has a stereo digital microphone. The mics are only 1cm apart
1512 * which makes the stereo useless. However, either the mic or the ALC889
1513 * makes the signal become a difference/sum signal instead of standard
1514 * stereo, which is annoying. So instead we flip this bit which makes the
1515 * codec replicate the sum signal to both channels, turning it into a
1516 * normal mono mic.
1517 */
1518/* DMIC_CONTROL? Init value = 0x0001 */
1519 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
1520 {0x20, AC_VERB_SET_PROC_COEF, 0x0003},
Hector Martin3b315d72009-06-02 10:54:19 +02001521 { }
1522};
1523
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001524static struct hda_input_mux alc888_2_capture_sources[2] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001525 /* Front mic only available on one ADC */
1526 {
1527 .num_items = 4,
1528 .items = {
1529 { "Mic", 0x0 },
1530 { "Line", 0x2 },
1531 { "CD", 0x4 },
1532 { "Front Mic", 0xb },
1533 },
1534 },
1535 {
1536 .num_items = 3,
1537 .items = {
1538 { "Mic", 0x0 },
1539 { "Line", 0x2 },
1540 { "CD", 0x4 },
1541 },
1542 }
1543};
1544
Hector Martin018df412009-06-04 00:13:40 +02001545static struct hda_input_mux alc889_capture_sources[3] = {
1546 /* Digital mic only available on first "ADC" */
1547 {
1548 .num_items = 5,
1549 .items = {
1550 { "Mic", 0x0 },
1551 { "Line", 0x2 },
1552 { "CD", 0x4 },
1553 { "Front Mic", 0xb },
1554 { "Input Mix", 0xa },
1555 },
1556 },
1557 {
1558 .num_items = 4,
1559 .items = {
1560 { "Mic", 0x0 },
1561 { "Line", 0x2 },
1562 { "CD", 0x4 },
1563 { "Input Mix", 0xa },
1564 },
1565 },
1566 {
1567 .num_items = 4,
1568 .items = {
1569 { "Mic", 0x0 },
1570 { "Line", 0x2 },
1571 { "CD", 0x4 },
1572 { "Input Mix", 0xa },
1573 },
1574 }
1575};
1576
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001577static struct snd_kcontrol_new alc888_base_mixer[] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001578 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1579 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
1580 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1581 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
1582 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
1583 HDA_OUTPUT),
1584 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1585 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1586 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1587 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
1588 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
1589 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1590 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1591 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1592 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1593 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1594 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
1595 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001596 { } /* end */
1597};
1598
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001599static void alc888_acer_aspire_4930g_init_hook(struct hda_codec *codec)
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001600{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001601 struct alc_spec *spec = codec->spec;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001602
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001603 spec->autocfg.hp_pins[0] = 0x15;
1604 spec->autocfg.speaker_pins[0] = 0x14;
1605 alc_automute_amp(codec);
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001606}
1607
Hector Martin018df412009-06-04 00:13:40 +02001608static void alc889_acer_aspire_8930g_init_hook(struct hda_codec *codec)
Hector Martin3b315d72009-06-02 10:54:19 +02001609{
1610 struct alc_spec *spec = codec->spec;
1611
1612 spec->autocfg.hp_pins[0] = 0x15;
1613 spec->autocfg.speaker_pins[0] = 0x14;
1614 spec->autocfg.speaker_pins[1] = 0x16;
1615 spec->autocfg.speaker_pins[2] = 0x1b;
1616 alc_automute_amp(codec);
1617}
1618
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001619/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001620 * ALC880 3-stack model
1621 *
1622 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001623 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
1624 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 */
1626
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001627static hda_nid_t alc880_dac_nids[4] = {
1628 /* front, rear, clfe, rear_surr */
1629 0x02, 0x05, 0x04, 0x03
1630};
1631
1632static hda_nid_t alc880_adc_nids[3] = {
1633 /* ADC0-2 */
1634 0x07, 0x08, 0x09,
1635};
1636
1637/* The datasheet says the node 0x07 is connected from inputs,
1638 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +01001639 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001641static hda_nid_t alc880_adc_nids_alt[2] = {
1642 /* ADC1-2 */
1643 0x08, 0x09,
1644};
1645
1646#define ALC880_DIGOUT_NID 0x06
1647#define ALC880_DIGIN_NID 0x0a
1648
1649static struct hda_input_mux alc880_capture_source = {
1650 .num_items = 4,
1651 .items = {
1652 { "Mic", 0x0 },
1653 { "Front Mic", 0x3 },
1654 { "Line", 0x2 },
1655 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001657};
1658
1659/* channel source setting (2/6 channel selection for 3-stack) */
1660/* 2ch mode */
1661static struct hda_verb alc880_threestack_ch2_init[] = {
1662 /* set line-in to input, mute it */
1663 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1664 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1665 /* set mic-in to input vref 80%, mute it */
1666 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1667 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 { } /* end */
1669};
1670
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001671/* 6ch mode */
1672static struct hda_verb alc880_threestack_ch6_init[] = {
1673 /* set line-in to output, unmute it */
1674 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1675 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1676 /* set mic-in to output, unmute it */
1677 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1678 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1679 { } /* end */
1680};
1681
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001682static struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001683 { 2, alc880_threestack_ch2_init },
1684 { 6, alc880_threestack_ch6_init },
1685};
1686
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001687static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001688 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001689 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001690 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001691 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001692 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1693 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001694 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1695 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1697 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1698 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1699 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1700 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1701 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1702 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
1703 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001705 {
1706 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1707 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001708 .info = alc_ch_mode_info,
1709 .get = alc_ch_mode_get,
1710 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001711 },
1712 { } /* end */
1713};
1714
1715/* capture mixer elements */
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001716static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
1717 struct snd_ctl_elem_info *uinfo)
1718{
1719 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1720 struct alc_spec *spec = codec->spec;
1721 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001722
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001723 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001724 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
1725 HDA_INPUT);
1726 err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001727 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001728 return err;
1729}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001731static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
1732 unsigned int size, unsigned int __user *tlv)
1733{
1734 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1735 struct alc_spec *spec = codec->spec;
1736 int err;
1737
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001738 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001739 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
1740 HDA_INPUT);
1741 err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001742 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001743 return err;
1744}
1745
1746typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
1747 struct snd_ctl_elem_value *ucontrol);
1748
1749static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
1750 struct snd_ctl_elem_value *ucontrol,
1751 getput_call_t func)
1752{
1753 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1754 struct alc_spec *spec = codec->spec;
1755 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1756 int err;
1757
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001758 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001759 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[adc_idx],
1760 3, 0, HDA_INPUT);
1761 err = func(kcontrol, ucontrol);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001762 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001763 return err;
1764}
1765
1766static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
1767 struct snd_ctl_elem_value *ucontrol)
1768{
1769 return alc_cap_getput_caller(kcontrol, ucontrol,
1770 snd_hda_mixer_amp_volume_get);
1771}
1772
1773static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
1774 struct snd_ctl_elem_value *ucontrol)
1775{
1776 return alc_cap_getput_caller(kcontrol, ucontrol,
1777 snd_hda_mixer_amp_volume_put);
1778}
1779
1780/* capture mixer elements */
1781#define alc_cap_sw_info snd_ctl_boolean_stereo_info
1782
1783static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
1784 struct snd_ctl_elem_value *ucontrol)
1785{
1786 return alc_cap_getput_caller(kcontrol, ucontrol,
1787 snd_hda_mixer_amp_switch_get);
1788}
1789
1790static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
1791 struct snd_ctl_elem_value *ucontrol)
1792{
1793 return alc_cap_getput_caller(kcontrol, ucontrol,
1794 snd_hda_mixer_amp_switch_put);
1795}
1796
Takashi Iwaia23b6882009-03-23 15:21:36 +01001797#define _DEFINE_CAPMIX(num) \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001798 { \
1799 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1800 .name = "Capture Switch", \
1801 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
1802 .count = num, \
1803 .info = alc_cap_sw_info, \
1804 .get = alc_cap_sw_get, \
1805 .put = alc_cap_sw_put, \
1806 }, \
1807 { \
1808 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1809 .name = "Capture Volume", \
1810 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
1811 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
1812 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
1813 .count = num, \
1814 .info = alc_cap_vol_info, \
1815 .get = alc_cap_vol_get, \
1816 .put = alc_cap_vol_put, \
1817 .tlv = { .c = alc_cap_vol_tlv }, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01001818 }
1819
1820#define _DEFINE_CAPSRC(num) \
Takashi Iwai3c3e9892008-10-31 17:48:56 +01001821 { \
1822 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1823 /* .name = "Capture Source", */ \
1824 .name = "Input Source", \
1825 .count = num, \
1826 .info = alc_mux_enum_info, \
1827 .get = alc_mux_enum_get, \
1828 .put = alc_mux_enum_put, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01001829 }
1830
1831#define DEFINE_CAPMIX(num) \
1832static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
1833 _DEFINE_CAPMIX(num), \
1834 _DEFINE_CAPSRC(num), \
1835 { } /* end */ \
1836}
1837
1838#define DEFINE_CAPMIX_NOSRC(num) \
1839static struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
1840 _DEFINE_CAPMIX(num), \
1841 { } /* end */ \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001842}
1843
1844/* up to three ADCs */
1845DEFINE_CAPMIX(1);
1846DEFINE_CAPMIX(2);
1847DEFINE_CAPMIX(3);
Takashi Iwaia23b6882009-03-23 15:21:36 +01001848DEFINE_CAPMIX_NOSRC(1);
1849DEFINE_CAPMIX_NOSRC(2);
1850DEFINE_CAPMIX_NOSRC(3);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001851
1852/*
1853 * ALC880 5-stack model
1854 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001855 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
1856 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001857 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
1858 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
1859 */
1860
1861/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001862static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001863 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001864 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 { } /* end */
1866};
1867
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001868/* channel source setting (6/8 channel selection for 5-stack) */
1869/* 6ch mode */
1870static struct hda_verb alc880_fivestack_ch6_init[] = {
1871 /* set line-in to input, mute it */
1872 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1873 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001874 { } /* end */
1875};
1876
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001877/* 8ch mode */
1878static struct hda_verb alc880_fivestack_ch8_init[] = {
1879 /* set line-in to output, unmute it */
1880 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1881 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1882 { } /* end */
1883};
1884
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001885static struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001886 { 6, alc880_fivestack_ch6_init },
1887 { 8, alc880_fivestack_ch8_init },
1888};
1889
1890
1891/*
1892 * ALC880 6-stack model
1893 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001894 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
1895 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001896 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
1897 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
1898 */
1899
1900static hda_nid_t alc880_6st_dac_nids[4] = {
1901 /* front, rear, clfe, rear_surr */
1902 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001903};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001904
1905static struct hda_input_mux alc880_6stack_capture_source = {
1906 .num_items = 4,
1907 .items = {
1908 { "Mic", 0x0 },
1909 { "Front Mic", 0x1 },
1910 { "Line", 0x2 },
1911 { "CD", 0x4 },
1912 },
1913};
1914
1915/* fixed 8-channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001916static struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001917 { 8, NULL },
1918};
1919
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001920static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001921 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001922 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001923 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001924 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001925 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1926 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001927 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1928 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001929 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001930 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001931 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1932 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1933 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1934 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1935 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1936 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1937 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1938 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001939 {
1940 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1941 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001942 .info = alc_ch_mode_info,
1943 .get = alc_ch_mode_get,
1944 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001945 },
1946 { } /* end */
1947};
1948
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001949
1950/*
1951 * ALC880 W810 model
1952 *
1953 * W810 has rear IO for:
1954 * Front (DAC 02)
1955 * Surround (DAC 03)
1956 * Center/LFE (DAC 04)
1957 * Digital out (06)
1958 *
1959 * The system also has a pair of internal speakers, and a headphone jack.
1960 * These are both connected to Line2 on the codec, hence to DAC 02.
Kailang Yangea1fb292008-08-26 12:58:38 +02001961 *
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001962 * There is a variable resistor to control the speaker or headphone
1963 * volume. This is a hardware-only device without a software API.
1964 *
1965 * Plugging headphones in will disable the internal speakers. This is
1966 * implemented in hardware, not via the driver using jack sense. In
1967 * a similar fashion, plugging into the rear socket marked "front" will
1968 * disable both the speakers and headphones.
1969 *
1970 * For input, there's a microphone jack, and an "audio in" jack.
1971 * These may not do anything useful with this driver yet, because I
1972 * haven't setup any initialization verbs for these yet...
1973 */
1974
1975static hda_nid_t alc880_w810_dac_nids[3] = {
1976 /* front, rear/surround, clfe */
1977 0x02, 0x03, 0x04
1978};
1979
1980/* fixed 6 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001981static struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001982 { 6, NULL }
1983};
1984
1985/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001986static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001987 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001988 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001989 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001990 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001991 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1992 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001993 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1994 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001995 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1996 { } /* end */
1997};
1998
1999
2000/*
2001 * Z710V model
2002 *
2003 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002004 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
2005 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002006 */
2007
2008static hda_nid_t alc880_z71v_dac_nids[1] = {
2009 0x02
2010};
2011#define ALC880_Z71V_HP_DAC 0x03
2012
2013/* fixed 2 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002014static struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002015 { 2, NULL }
2016};
2017
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002018static struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002019 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002020 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002021 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002022 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002023 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2024 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2025 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2026 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2027 { } /* end */
2028};
2029
2030
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002031/*
2032 * ALC880 F1734 model
2033 *
2034 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
2035 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
2036 */
2037
2038static hda_nid_t alc880_f1734_dac_nids[1] = {
2039 0x03
2040};
2041#define ALC880_F1734_HP_DAC 0x02
2042
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002043static struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002044 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002045 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01002046 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2047 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002048 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2049 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01002050 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2051 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002052 { } /* end */
2053};
2054
Takashi Iwai937b4162008-02-11 14:52:36 +01002055static struct hda_input_mux alc880_f1734_capture_source = {
2056 .num_items = 2,
2057 .items = {
2058 { "Mic", 0x1 },
2059 { "CD", 0x4 },
2060 },
2061};
2062
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002063
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002064/*
2065 * ALC880 ASUS model
2066 *
2067 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
2068 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
2069 * Mic = 0x18, Line = 0x1a
2070 */
2071
2072#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
2073#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
2074
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002075static struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002076 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002077 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002078 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002079 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002080 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2081 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002082 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2083 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002084 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2085 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2086 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2087 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2088 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2089 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002090 {
2091 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2092 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002093 .info = alc_ch_mode_info,
2094 .get = alc_ch_mode_get,
2095 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02002096 },
2097 { } /* end */
2098};
2099
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002100/*
2101 * ALC880 ASUS W1V model
2102 *
2103 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
2104 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
2105 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
2106 */
2107
2108/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002109static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002110 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
2111 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002112 { } /* end */
2113};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002114
Kailang Yangdf694da2005-12-05 19:42:22 +01002115/* TCL S700 */
2116static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
2117 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2118 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
2119 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
2120 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
2121 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
2122 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
2123 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
2124 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
2125 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01002126 { } /* end */
2127};
2128
Kailang Yangccc656c2006-10-17 12:32:26 +02002129/* Uniwill */
2130static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002131 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2132 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2133 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2134 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002135 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2136 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2137 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2138 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2139 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2140 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2141 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2142 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2143 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2144 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2145 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2146 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002147 {
2148 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2149 .name = "Channel Mode",
2150 .info = alc_ch_mode_info,
2151 .get = alc_ch_mode_get,
2152 .put = alc_ch_mode_put,
2153 },
2154 { } /* end */
2155};
2156
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002157static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
2158 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2159 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2160 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2161 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
2162 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2163 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2164 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2165 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2166 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2167 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
2168 { } /* end */
2169};
2170
Kailang Yangccc656c2006-10-17 12:32:26 +02002171static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002172 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2173 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2174 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2175 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002176 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2177 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2178 { } /* end */
2179};
2180
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01002182 * virtual master controls
2183 */
2184
2185/*
2186 * slave controls for virtual master
2187 */
2188static const char *alc_slave_vols[] = {
2189 "Front Playback Volume",
2190 "Surround Playback Volume",
2191 "Center Playback Volume",
2192 "LFE Playback Volume",
2193 "Side Playback Volume",
2194 "Headphone Playback Volume",
2195 "Speaker Playback Volume",
2196 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002197 "Line-Out Playback Volume",
Takashi Iwai26f5df22008-11-03 17:39:46 +01002198 "PCM Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002199 NULL,
2200};
2201
2202static const char *alc_slave_sws[] = {
2203 "Front Playback Switch",
2204 "Surround Playback Switch",
2205 "Center Playback Switch",
2206 "LFE Playback Switch",
2207 "Side Playback Switch",
2208 "Headphone Playback Switch",
2209 "Speaker Playback Switch",
2210 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01002211 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002212 NULL,
2213};
2214
2215/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002216 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217 */
Takashi Iwai603c4012008-07-30 15:01:44 +02002218
2219static void alc_free_kctls(struct hda_codec *codec);
2220
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002221/* additional beep mixers; the actual parameters are overwritten at build */
2222static struct snd_kcontrol_new alc_beep_mixer[] = {
2223 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
2224 HDA_CODEC_MUTE("Beep Playback Switch", 0, 0, HDA_INPUT),
2225 { } /* end */
2226};
2227
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228static int alc_build_controls(struct hda_codec *codec)
2229{
2230 struct alc_spec *spec = codec->spec;
2231 int err;
2232 int i;
2233
2234 for (i = 0; i < spec->num_mixers; i++) {
2235 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
2236 if (err < 0)
2237 return err;
2238 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002239 if (spec->cap_mixer) {
2240 err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
2241 if (err < 0)
2242 return err;
2243 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002245 err = snd_hda_create_spdif_out_ctls(codec,
2246 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 if (err < 0)
2248 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002249 if (!spec->no_analog) {
2250 err = snd_hda_create_spdif_share_sw(codec,
2251 &spec->multiout);
2252 if (err < 0)
2253 return err;
2254 spec->multiout.share_spdif = 1;
2255 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 }
2257 if (spec->dig_in_nid) {
2258 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
2259 if (err < 0)
2260 return err;
2261 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01002262
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002263 /* create beep controls if needed */
2264 if (spec->beep_amp) {
2265 struct snd_kcontrol_new *knew;
2266 for (knew = alc_beep_mixer; knew->name; knew++) {
2267 struct snd_kcontrol *kctl;
2268 kctl = snd_ctl_new1(knew, codec);
2269 if (!kctl)
2270 return -ENOMEM;
2271 kctl->private_value = spec->beep_amp;
2272 err = snd_hda_ctl_add(codec, kctl);
2273 if (err < 0)
2274 return err;
2275 }
2276 }
2277
Takashi Iwai2134ea42008-01-10 16:53:55 +01002278 /* if we have no master control, let's create it */
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002279 if (!spec->no_analog &&
2280 !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002281 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01002282 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002283 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01002284 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002285 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01002286 if (err < 0)
2287 return err;
2288 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002289 if (!spec->no_analog &&
2290 !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002291 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
2292 NULL, alc_slave_sws);
2293 if (err < 0)
2294 return err;
2295 }
2296
Takashi Iwai603c4012008-07-30 15:01:44 +02002297 alc_free_kctls(codec); /* no longer needed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 return 0;
2299}
2300
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002301
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302/*
2303 * initialize the codec volumes, etc
2304 */
2305
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002306/*
2307 * generic initialization of ADC, input mixers and output mixers
2308 */
2309static struct hda_verb alc880_volume_init_verbs[] = {
2310 /*
2311 * Unmute ADC0-2 and set the default input to mic-in
2312 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002313 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002314 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002315 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002316 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002317 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002318 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002320 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2321 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002322 * Note: PASD motherboards uses the Line In 2 as the input for front
2323 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002325 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02002326 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2327 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2328 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2329 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2330 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2331 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2332 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002334 /*
2335 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002337 /* set vol=0 to output mixers */
2338 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2339 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2340 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2341 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2342 /* set up input amps for analog loopback */
2343 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002344 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2345 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002346 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2347 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002348 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2349 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002350 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2351 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352
2353 { }
2354};
2355
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002356/*
2357 * 3-stack pin configuration:
2358 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
2359 */
2360static struct hda_verb alc880_pin_3stack_init_verbs[] = {
2361 /*
2362 * preset connection lists of input pins
2363 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
2364 */
2365 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
2366 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2367 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
2368
2369 /*
2370 * Set pin mode and muting
2371 */
2372 /* set front pin widgets 0x14 for output */
2373 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2374 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2375 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2376 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2377 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2378 /* Mic2 (as headphone out) for HP output */
2379 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2380 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2381 /* Line In pin widget for input */
2382 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2383 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2384 /* Line2 (as front mic) pin widget for input and vref at 80% */
2385 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2386 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2387 /* CD pin widget for input */
2388 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2389
2390 { }
2391};
2392
2393/*
2394 * 5-stack pin configuration:
2395 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
2396 * line-in/side = 0x1a, f-mic = 0x1b
2397 */
2398static struct hda_verb alc880_pin_5stack_init_verbs[] = {
2399 /*
2400 * preset connection lists of input pins
2401 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
2402 */
2403 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2404 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
2405
2406 /*
2407 * Set pin mode and muting
2408 */
2409 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02002410 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2411 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2412 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2413 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002414 /* unmute pins for output (no gain on this amp) */
2415 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2416 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2417 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2418 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2419
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02002421 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002422 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2423 /* Mic2 (as headphone out) for HP output */
2424 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02002425 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002426 /* Line In pin widget for input */
2427 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2428 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2429 /* Line2 (as front mic) pin widget for input and vref at 80% */
2430 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2431 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2432 /* CD pin widget for input */
2433 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434
2435 { }
2436};
2437
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002438/*
2439 * W810 pin configuration:
2440 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
2441 */
2442static struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 /* hphone/speaker input selector: front DAC */
2444 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
2445
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002446 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2447 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2448 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2449 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2450 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2451 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2452
2453 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02002454 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 { }
2457};
2458
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002459/*
2460 * Z71V pin configuration:
2461 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
2462 */
2463static struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002464 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002465 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02002466 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002467 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002468
Takashi Iwai16ded522005-06-10 19:58:24 +02002469 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002470 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02002471 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002472 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002473
2474 { }
2475};
2476
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002477/*
2478 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002479 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
2480 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002481 */
2482static struct hda_verb alc880_pin_6stack_init_verbs[] = {
2483 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2484
Takashi Iwai16ded522005-06-10 19:58:24 +02002485 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002486 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002487 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002488 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002489 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002490 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002491 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002492 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2493
Takashi Iwai16ded522005-06-10 19:58:24 +02002494 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002495 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002496 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002497 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002498 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002499 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002500 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02002501 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002502 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02002503
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002504 { }
2505};
Takashi Iwai16ded522005-06-10 19:58:24 +02002506
Kailang Yangccc656c2006-10-17 12:32:26 +02002507/*
2508 * Uniwill pin configuration:
2509 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
2510 * line = 0x1a
2511 */
2512static struct hda_verb alc880_uniwill_init_verbs[] = {
2513 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2514
2515 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2516 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2517 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2518 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2519 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2520 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2521 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2522 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2523 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2524 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2525 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2526 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2527 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2528 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2529
2530 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2531 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2532 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2533 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2534 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2535 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2536 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
2537 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
2538 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2539
2540 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2541 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
2542
2543 { }
2544};
2545
2546/*
2547* Uniwill P53
Kailang Yangea1fb292008-08-26 12:58:38 +02002548* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
Kailang Yangccc656c2006-10-17 12:32:26 +02002549 */
2550static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
2551 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2552
2553 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2554 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2555 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2556 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2557 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2558 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2559 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2560 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2561 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2562 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2563 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2564 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2565
2566 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2567 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2568 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2569 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2570 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2571 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2572
2573 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2574 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
2575
2576 { }
2577};
2578
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002579static struct hda_verb alc880_beep_init_verbs[] = {
2580 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
2581 { }
2582};
2583
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002584/* auto-toggle front mic */
2585static void alc880_uniwill_mic_automute(struct hda_codec *codec)
2586{
2587 unsigned int present;
2588 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02002589
2590 present = snd_hda_codec_read(codec, 0x18, 0,
2591 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002592 bits = present ? HDA_AMP_MUTE : 0;
2593 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002594}
2595
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002596static void alc880_uniwill_init_hook(struct hda_codec *codec)
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002597{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002598 struct alc_spec *spec = codec->spec;
2599
2600 spec->autocfg.hp_pins[0] = 0x14;
2601 spec->autocfg.speaker_pins[0] = 0x15;
2602 spec->autocfg.speaker_pins[0] = 0x16;
2603 alc_automute_amp(codec);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002604 alc880_uniwill_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02002605}
2606
2607static void alc880_uniwill_unsol_event(struct hda_codec *codec,
2608 unsigned int res)
2609{
2610 /* Looks like the unsol event is incompatible with the standard
2611 * definition. 4bit tag is placed at 28 bit!
2612 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002613 switch (res >> 28) {
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002614 case ALC880_MIC_EVENT:
2615 alc880_uniwill_mic_automute(codec);
2616 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002617 default:
2618 alc_automute_amp_unsol_event(codec, res);
2619 break;
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002620 }
Kailang Yangccc656c2006-10-17 12:32:26 +02002621}
2622
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002623static void alc880_uniwill_p53_init_hook(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02002624{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002625 struct alc_spec *spec = codec->spec;
Kailang Yangccc656c2006-10-17 12:32:26 +02002626
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002627 spec->autocfg.hp_pins[0] = 0x14;
2628 spec->autocfg.speaker_pins[0] = 0x15;
2629 alc_automute_amp(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02002630}
2631
2632static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
2633{
2634 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02002635
Kailang Yangccc656c2006-10-17 12:32:26 +02002636 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02002637 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
2638 present &= HDA_AMP_VOLMASK;
2639 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
2640 HDA_AMP_VOLMASK, present);
2641 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
2642 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02002643}
Takashi Iwai47fd8302007-08-10 17:11:07 +02002644
Kailang Yangccc656c2006-10-17 12:32:26 +02002645static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
2646 unsigned int res)
2647{
2648 /* Looks like the unsol event is incompatible with the standard
2649 * definition. 4bit tag is placed at 28 bit!
2650 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002651 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02002652 alc880_uniwill_p53_dcvol_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002653 else
2654 alc_automute_amp_unsol_event(codec, res);
Kailang Yangccc656c2006-10-17 12:32:26 +02002655}
2656
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002657/*
2658 * F1734 pin configuration:
2659 * HP = 0x14, speaker-out = 0x15, mic = 0x18
2660 */
2661static struct hda_verb alc880_pin_f1734_init_verbs[] = {
Michael Gruberee7a9c72008-03-10 11:30:59 +01002662 {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002663 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
2664 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
2665 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
2666 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
2667
2668 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2669 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2670 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2671 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2672
2673 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2674 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Michael Gruberee7a9c72008-03-10 11:30:59 +01002675 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002676 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2677 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2678 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2679 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2680 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2681 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02002682
Takashi Iwai937b4162008-02-11 14:52:36 +01002683 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
2684 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
2685
Takashi Iwai16ded522005-06-10 19:58:24 +02002686 { }
2687};
2688
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002689/*
2690 * ASUS pin configuration:
2691 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
2692 */
2693static struct hda_verb alc880_pin_asus_init_verbs[] = {
2694 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
2695 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
2696 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
2697 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
2698
2699 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2700 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2701 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2702 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2703 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2704 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2705 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2706 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2707
2708 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2709 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2710 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2711 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2712 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2713 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2714 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2715 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2716 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02002717
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002718 { }
2719};
2720
2721/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02002722#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
2723#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002724
Kailang Yangdf694da2005-12-05 19:42:22 +01002725/* Clevo m520g init */
2726static struct hda_verb alc880_pin_clevo_init_verbs[] = {
2727 /* headphone output */
2728 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
2729 /* line-out */
2730 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2731 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2732 /* Line-in */
2733 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2734 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2735 /* CD */
2736 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2737 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2738 /* Mic1 (rear panel) */
2739 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2740 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2741 /* Mic2 (front panel) */
2742 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2743 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2744 /* headphone */
2745 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2746 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2747 /* change to EAPD mode */
2748 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2749 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2750
2751 { }
2752};
2753
2754static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02002755 /* change to EAPD mode */
2756 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2757 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2758
Kailang Yangdf694da2005-12-05 19:42:22 +01002759 /* Headphone output */
2760 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2761 /* Front output*/
2762 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2763 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
2764
2765 /* Line In pin widget for input */
2766 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2767 /* CD pin widget for input */
2768 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2769 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2770 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2771
2772 /* change to EAPD mode */
2773 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2774 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
2775
2776 { }
2777};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002778
2779/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002780 * LG m1 express dual
2781 *
2782 * Pin assignment:
2783 * Rear Line-In/Out (blue): 0x14
2784 * Build-in Mic-In: 0x15
2785 * Speaker-out: 0x17
2786 * HP-Out (green): 0x1b
2787 * Mic-In/Out (red): 0x19
2788 * SPDIF-Out: 0x1e
2789 */
2790
2791/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
2792static hda_nid_t alc880_lg_dac_nids[3] = {
2793 0x05, 0x02, 0x03
2794};
2795
2796/* seems analog CD is not working */
2797static struct hda_input_mux alc880_lg_capture_source = {
2798 .num_items = 3,
2799 .items = {
2800 { "Mic", 0x1 },
2801 { "Line", 0x5 },
2802 { "Internal Mic", 0x6 },
2803 },
2804};
2805
2806/* 2,4,6 channel modes */
2807static struct hda_verb alc880_lg_ch2_init[] = {
2808 /* set line-in and mic-in to input */
2809 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2810 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2811 { }
2812};
2813
2814static struct hda_verb alc880_lg_ch4_init[] = {
2815 /* set line-in to out and mic-in to input */
2816 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2817 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2818 { }
2819};
2820
2821static struct hda_verb alc880_lg_ch6_init[] = {
2822 /* set line-in and mic-in to output */
2823 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2824 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2825 { }
2826};
2827
2828static struct hda_channel_mode alc880_lg_ch_modes[3] = {
2829 { 2, alc880_lg_ch2_init },
2830 { 4, alc880_lg_ch4_init },
2831 { 6, alc880_lg_ch6_init },
2832};
2833
2834static struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002835 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2836 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002837 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2838 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
2839 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
2840 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
2841 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
2842 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
2843 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2844 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
2845 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
2846 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
2847 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
2848 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
2849 {
2850 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2851 .name = "Channel Mode",
2852 .info = alc_ch_mode_info,
2853 .get = alc_ch_mode_get,
2854 .put = alc_ch_mode_put,
2855 },
2856 { } /* end */
2857};
2858
2859static struct hda_verb alc880_lg_init_verbs[] = {
2860 /* set capture source to mic-in */
2861 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2862 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2863 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2864 /* mute all amp mixer inputs */
2865 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002866 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2867 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002868 /* line-in to input */
2869 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2870 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2871 /* built-in mic */
2872 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2873 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2874 /* speaker-out */
2875 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2876 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2877 /* mic-in to input */
2878 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
2879 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2880 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2881 /* HP-out */
2882 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
2883 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2884 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2885 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002886 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002887 { }
2888};
2889
2890/* toggle speaker-output according to the hp-jack state */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002891static void alc880_lg_init_hook(struct hda_codec *codec)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002892{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002893 struct alc_spec *spec = codec->spec;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002894
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002895 spec->autocfg.hp_pins[0] = 0x1b;
2896 spec->autocfg.speaker_pins[0] = 0x17;
2897 alc_automute_amp(codec);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002898}
2899
2900/*
Takashi Iwaid6815182006-03-23 16:06:23 +01002901 * LG LW20
2902 *
2903 * Pin assignment:
2904 * Speaker-out: 0x14
2905 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002906 * Built-in Mic-In: 0x19
2907 * Line-In: 0x1b
2908 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01002909 * SPDIF-Out: 0x1e
2910 */
2911
Takashi Iwaid6815182006-03-23 16:06:23 +01002912static struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002913 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01002914 .items = {
2915 { "Mic", 0x0 },
2916 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002917 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002918 },
2919};
2920
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002921#define alc880_lg_lw_modes alc880_threestack_modes
2922
Takashi Iwaid6815182006-03-23 16:06:23 +01002923static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002924 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2925 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2926 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2927 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
2928 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2929 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2930 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2931 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2932 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2933 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01002934 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2935 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2936 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
2937 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002938 {
2939 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2940 .name = "Channel Mode",
2941 .info = alc_ch_mode_info,
2942 .get = alc_ch_mode_get,
2943 .put = alc_ch_mode_put,
2944 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002945 { } /* end */
2946};
2947
2948static struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002949 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2950 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
2951 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
2952
Takashi Iwaid6815182006-03-23 16:06:23 +01002953 /* set capture source to mic-in */
2954 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2955 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2956 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002957 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01002958 /* speaker-out */
2959 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2960 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2961 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01002962 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2963 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2964 /* mic-in to input */
2965 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2966 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2967 /* built-in mic */
2968 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2969 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2970 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002971 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaid6815182006-03-23 16:06:23 +01002972 { }
2973};
2974
2975/* toggle speaker-output according to the hp-jack state */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002976static void alc880_lg_lw_init_hook(struct hda_codec *codec)
Takashi Iwaid6815182006-03-23 16:06:23 +01002977{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002978 struct alc_spec *spec = codec->spec;
Takashi Iwaid6815182006-03-23 16:06:23 +01002979
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002980 spec->autocfg.hp_pins[0] = 0x1b;
2981 spec->autocfg.speaker_pins[0] = 0x14;
2982 alc_automute_amp(codec);
Takashi Iwaid6815182006-03-23 16:06:23 +01002983}
2984
Takashi Iwaidf99cd32008-04-25 15:25:04 +02002985static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
2986 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2987 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
2988 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2989 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2990 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2991 HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
2992 { } /* end */
2993};
2994
2995static struct hda_input_mux alc880_medion_rim_capture_source = {
2996 .num_items = 2,
2997 .items = {
2998 { "Mic", 0x0 },
2999 { "Internal Mic", 0x1 },
3000 },
3001};
3002
3003static struct hda_verb alc880_medion_rim_init_verbs[] = {
3004 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3005
3006 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3007 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3008
3009 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3010 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3011 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3012 /* Mic2 (as headphone out) for HP output */
3013 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3014 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3015 /* Internal Speaker */
3016 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3017 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3018
3019 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3020 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3021
3022 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3023 { }
3024};
3025
3026/* toggle speaker-output according to the hp-jack state */
3027static void alc880_medion_rim_automute(struct hda_codec *codec)
3028{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003029 struct alc_spec *spec = codec->spec;
3030 alc_automute_amp(codec);
3031 /* toggle EAPD */
3032 if (spec->jack_present)
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003033 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
3034 else
3035 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
3036}
3037
3038static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
3039 unsigned int res)
3040{
3041 /* Looks like the unsol event is incompatible with the standard
3042 * definition. 4bit tag is placed at 28 bit!
3043 */
3044 if ((res >> 28) == ALC880_HP_EVENT)
3045 alc880_medion_rim_automute(codec);
3046}
3047
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003048static void alc880_medion_rim_init_hook(struct hda_codec *codec)
3049{
3050 struct alc_spec *spec = codec->spec;
3051
3052 spec->autocfg.hp_pins[0] = 0x14;
3053 spec->autocfg.speaker_pins[0] = 0x1b;
3054 alc880_medion_rim_automute(codec);
3055}
3056
Takashi Iwaicb53c622007-08-10 17:21:45 +02003057#ifdef CONFIG_SND_HDA_POWER_SAVE
3058static struct hda_amp_list alc880_loopbacks[] = {
3059 { 0x0b, HDA_INPUT, 0 },
3060 { 0x0b, HDA_INPUT, 1 },
3061 { 0x0b, HDA_INPUT, 2 },
3062 { 0x0b, HDA_INPUT, 3 },
3063 { 0x0b, HDA_INPUT, 4 },
3064 { } /* end */
3065};
3066
3067static struct hda_amp_list alc880_lg_loopbacks[] = {
3068 { 0x0b, HDA_INPUT, 1 },
3069 { 0x0b, HDA_INPUT, 6 },
3070 { 0x0b, HDA_INPUT, 7 },
3071 { } /* end */
3072};
3073#endif
3074
Takashi Iwaid6815182006-03-23 16:06:23 +01003075/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003076 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003077 */
Takashi Iwai16ded522005-06-10 19:58:24 +02003078
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079static int alc_init(struct hda_codec *codec)
3080{
3081 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003082 unsigned int i;
3083
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02003084 alc_fix_pll(codec);
Takashi Iwai4a79ba342009-04-22 16:31:35 +02003085 alc_auto_init_amp(codec, spec->init_amp);
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02003086
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003087 for (i = 0; i < spec->num_init_verbs; i++)
3088 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003089
3090 if (spec->init_hook)
3091 spec->init_hook(codec);
3092
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 return 0;
3094}
3095
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003096static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
3097{
3098 struct alc_spec *spec = codec->spec;
3099
3100 if (spec->unsol_event)
3101 spec->unsol_event(codec, res);
3102}
3103
Takashi Iwaicb53c622007-08-10 17:21:45 +02003104#ifdef CONFIG_SND_HDA_POWER_SAVE
3105static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
3106{
3107 struct alc_spec *spec = codec->spec;
3108 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
3109}
3110#endif
3111
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112/*
3113 * Analog playback callbacks
3114 */
3115static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
3116 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003117 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118{
3119 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01003120 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
3121 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122}
3123
3124static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
3125 struct hda_codec *codec,
3126 unsigned int stream_tag,
3127 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003128 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129{
3130 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003131 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
3132 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133}
3134
3135static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3136 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003137 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138{
3139 struct alc_spec *spec = codec->spec;
3140 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
3141}
3142
3143/*
3144 * Digital out
3145 */
3146static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
3147 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003148 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149{
3150 struct alc_spec *spec = codec->spec;
3151 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
3152}
3153
Takashi Iwai6b97eb42007-04-05 14:51:48 +02003154static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
3155 struct hda_codec *codec,
3156 unsigned int stream_tag,
3157 unsigned int format,
3158 struct snd_pcm_substream *substream)
3159{
3160 struct alc_spec *spec = codec->spec;
3161 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
3162 stream_tag, format, substream);
3163}
3164
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01003165static int alc880_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3166 struct hda_codec *codec,
3167 struct snd_pcm_substream *substream)
3168{
3169 struct alc_spec *spec = codec->spec;
3170 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
3171}
3172
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
3174 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003175 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176{
3177 struct alc_spec *spec = codec->spec;
3178 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
3179}
3180
3181/*
3182 * Analog capture
3183 */
Takashi Iwai63300792008-01-24 15:31:36 +01003184static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 struct hda_codec *codec,
3186 unsigned int stream_tag,
3187 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003188 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189{
3190 struct alc_spec *spec = codec->spec;
3191
Takashi Iwai63300792008-01-24 15:31:36 +01003192 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193 stream_tag, 0, format);
3194 return 0;
3195}
3196
Takashi Iwai63300792008-01-24 15:31:36 +01003197static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003199 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200{
3201 struct alc_spec *spec = codec->spec;
3202
Takashi Iwai888afa12008-03-18 09:57:50 +01003203 snd_hda_codec_cleanup_stream(codec,
3204 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205 return 0;
3206}
3207
3208
3209/*
3210 */
3211static struct hda_pcm_stream alc880_pcm_analog_playback = {
3212 .substreams = 1,
3213 .channels_min = 2,
3214 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003215 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216 .ops = {
3217 .open = alc880_playback_pcm_open,
3218 .prepare = alc880_playback_pcm_prepare,
3219 .cleanup = alc880_playback_pcm_cleanup
3220 },
3221};
3222
3223static struct hda_pcm_stream alc880_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01003224 .substreams = 1,
3225 .channels_min = 2,
3226 .channels_max = 2,
3227 /* NID is set in alc_build_pcms */
3228};
3229
3230static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
3231 .substreams = 1,
3232 .channels_min = 2,
3233 .channels_max = 2,
3234 /* NID is set in alc_build_pcms */
3235};
3236
3237static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
3238 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239 .channels_min = 2,
3240 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003241 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242 .ops = {
Takashi Iwai63300792008-01-24 15:31:36 +01003243 .prepare = alc880_alt_capture_pcm_prepare,
3244 .cleanup = alc880_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245 },
3246};
3247
3248static struct hda_pcm_stream alc880_pcm_digital_playback = {
3249 .substreams = 1,
3250 .channels_min = 2,
3251 .channels_max = 2,
3252 /* NID is set in alc_build_pcms */
3253 .ops = {
3254 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02003255 .close = alc880_dig_playback_pcm_close,
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01003256 .prepare = alc880_dig_playback_pcm_prepare,
3257 .cleanup = alc880_dig_playback_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 },
3259};
3260
3261static struct hda_pcm_stream alc880_pcm_digital_capture = {
3262 .substreams = 1,
3263 .channels_min = 2,
3264 .channels_max = 2,
3265 /* NID is set in alc_build_pcms */
3266};
3267
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003268/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwai63300792008-01-24 15:31:36 +01003269static struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003270 .substreams = 0,
3271 .channels_min = 0,
3272 .channels_max = 0,
3273};
3274
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275static int alc_build_pcms(struct hda_codec *codec)
3276{
3277 struct alc_spec *spec = codec->spec;
3278 struct hda_pcm *info = spec->pcm_rec;
3279 int i;
3280
3281 codec->num_pcms = 1;
3282 codec->pcm_info = info;
3283
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003284 if (spec->no_analog)
3285 goto skip_analog;
3286
Takashi Iwai812a2cc2009-05-16 10:00:49 +02003287 snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog),
3288 "%s Analog", codec->chip_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289 info->name = spec->stream_name_analog;
Takashi Iwai812a2cc2009-05-16 10:00:49 +02003290
Takashi Iwai4a471b72005-12-07 13:56:29 +01003291 if (spec->stream_analog_playback) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02003292 if (snd_BUG_ON(!spec->multiout.dac_nids))
3293 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003294 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
3295 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
3296 }
3297 if (spec->stream_analog_capture) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02003298 if (snd_BUG_ON(!spec->adc_nids))
3299 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003300 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
3301 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
3302 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303
Takashi Iwai4a471b72005-12-07 13:56:29 +01003304 if (spec->channel_mode) {
3305 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
3306 for (i = 0; i < spec->num_channel_mode; i++) {
3307 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
3308 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
3309 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310 }
3311 }
3312
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003313 skip_analog:
Takashi Iwaie08a0072006-09-07 17:52:14 +02003314 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwai812a2cc2009-05-16 10:00:49 +02003316 snprintf(spec->stream_name_digital,
3317 sizeof(spec->stream_name_digital),
3318 "%s Digital", codec->chip_name);
Takashi Iwaie08a0072006-09-07 17:52:14 +02003319 codec->num_pcms = 2;
Wu Fengguangb25c9da2009-02-06 15:02:27 +08003320 codec->slave_dig_outs = spec->multiout.slave_dig_outs;
Takashi Iwaic06134d2006-10-11 18:49:13 +02003321 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322 info->name = spec->stream_name_digital;
Takashi Iwai8c441982009-01-20 18:30:20 +01003323 if (spec->dig_out_type)
3324 info->pcm_type = spec->dig_out_type;
3325 else
3326 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003327 if (spec->multiout.dig_out_nid &&
3328 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
3330 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
3331 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01003332 if (spec->dig_in_nid &&
3333 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
3335 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
3336 }
Takashi Iwai963f8032008-08-11 10:04:40 +02003337 /* FIXME: do we need this for all Realtek codec models? */
3338 codec->spdif_status_reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 }
3340
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003341 if (spec->no_analog)
3342 return 0;
3343
Takashi Iwaie08a0072006-09-07 17:52:14 +02003344 /* If the use of more than one ADC is requested for the current
3345 * model, configure a second analog capture-only PCM.
3346 */
3347 /* Additional Analaog capture for index #2 */
Takashi Iwai63300792008-01-24 15:31:36 +01003348 if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
3349 (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02003350 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02003351 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02003352 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01003353 if (spec->alt_dac_nid) {
3354 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
3355 *spec->stream_analog_alt_playback;
3356 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
3357 spec->alt_dac_nid;
3358 } else {
3359 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
3360 alc_pcm_null_stream;
3361 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
3362 }
3363 if (spec->num_adc_nids > 1) {
3364 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
3365 *spec->stream_analog_alt_capture;
3366 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
3367 spec->adc_nids[1];
3368 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
3369 spec->num_adc_nids - 1;
3370 } else {
3371 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
3372 alc_pcm_null_stream;
3373 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02003374 }
3375 }
3376
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377 return 0;
3378}
3379
Takashi Iwai603c4012008-07-30 15:01:44 +02003380static void alc_free_kctls(struct hda_codec *codec)
3381{
3382 struct alc_spec *spec = codec->spec;
3383
3384 if (spec->kctls.list) {
3385 struct snd_kcontrol_new *kctl = spec->kctls.list;
3386 int i;
3387 for (i = 0; i < spec->kctls.used; i++)
3388 kfree(kctl[i].name);
3389 }
3390 snd_array_free(&spec->kctls);
3391}
3392
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393static void alc_free(struct hda_codec *codec)
3394{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003395 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003396
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003397 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003398 return;
3399
Takashi Iwai603c4012008-07-30 15:01:44 +02003400 alc_free_kctls(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003401 kfree(spec);
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09003402 snd_hda_detach_beep_device(codec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403}
3404
Takashi Iwaie044c392008-10-27 16:56:24 +01003405#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaie044c392008-10-27 16:56:24 +01003406static int alc_resume(struct hda_codec *codec)
3407{
Takashi Iwaie044c392008-10-27 16:56:24 +01003408 codec->patch_ops.init(codec);
3409 snd_hda_codec_resume_amp(codec);
3410 snd_hda_codec_resume_cache(codec);
3411 return 0;
3412}
Takashi Iwaie044c392008-10-27 16:56:24 +01003413#endif
3414
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415/*
3416 */
3417static struct hda_codec_ops alc_patch_ops = {
3418 .build_controls = alc_build_controls,
3419 .build_pcms = alc_build_pcms,
3420 .init = alc_init,
3421 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003422 .unsol_event = alc_unsol_event,
Takashi Iwaie044c392008-10-27 16:56:24 +01003423#ifdef SND_HDA_NEEDS_RESUME
3424 .resume = alc_resume,
3425#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02003426#ifdef CONFIG_SND_HDA_POWER_SAVE
3427 .check_power_status = alc_check_power_status,
3428#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429};
3430
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003431
3432/*
3433 * Test configuration for debugging
3434 *
3435 * Almost all inputs/outputs are enabled. I/O pins can be configured via
3436 * enum controls.
3437 */
3438#ifdef CONFIG_SND_DEBUG
3439static hda_nid_t alc880_test_dac_nids[4] = {
3440 0x02, 0x03, 0x04, 0x05
3441};
3442
3443static struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003444 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003445 .items = {
3446 { "In-1", 0x0 },
3447 { "In-2", 0x1 },
3448 { "In-3", 0x2 },
3449 { "In-4", 0x3 },
3450 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003451 { "Front", 0x5 },
3452 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003453 },
3454};
3455
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01003456static struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003457 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02003458 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003459 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02003460 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003461};
3462
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003463static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
3464 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003465{
3466 static char *texts[] = {
3467 "N/A", "Line Out", "HP Out",
3468 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
3469 };
3470 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3471 uinfo->count = 1;
3472 uinfo->value.enumerated.items = 8;
3473 if (uinfo->value.enumerated.item >= 8)
3474 uinfo->value.enumerated.item = 7;
3475 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
3476 return 0;
3477}
3478
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003479static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
3480 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003481{
3482 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3483 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3484 unsigned int pin_ctl, item = 0;
3485
3486 pin_ctl = snd_hda_codec_read(codec, nid, 0,
3487 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3488 if (pin_ctl & AC_PINCTL_OUT_EN) {
3489 if (pin_ctl & AC_PINCTL_HP_EN)
3490 item = 2;
3491 else
3492 item = 1;
3493 } else if (pin_ctl & AC_PINCTL_IN_EN) {
3494 switch (pin_ctl & AC_PINCTL_VREFEN) {
3495 case AC_PINCTL_VREF_HIZ: item = 3; break;
3496 case AC_PINCTL_VREF_50: item = 4; break;
3497 case AC_PINCTL_VREF_GRD: item = 5; break;
3498 case AC_PINCTL_VREF_80: item = 6; break;
3499 case AC_PINCTL_VREF_100: item = 7; break;
3500 }
3501 }
3502 ucontrol->value.enumerated.item[0] = item;
3503 return 0;
3504}
3505
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003506static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
3507 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003508{
3509 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3510 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3511 static unsigned int ctls[] = {
3512 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
3513 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
3514 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
3515 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
3516 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
3517 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
3518 };
3519 unsigned int old_ctl, new_ctl;
3520
3521 old_ctl = snd_hda_codec_read(codec, nid, 0,
3522 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3523 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
3524 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003525 int val;
3526 snd_hda_codec_write_cache(codec, nid, 0,
3527 AC_VERB_SET_PIN_WIDGET_CONTROL,
3528 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02003529 val = ucontrol->value.enumerated.item[0] >= 3 ?
3530 HDA_AMP_MUTE : 0;
3531 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
3532 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003533 return 1;
3534 }
3535 return 0;
3536}
3537
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003538static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
3539 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003540{
3541 static char *texts[] = {
3542 "Front", "Surround", "CLFE", "Side"
3543 };
3544 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3545 uinfo->count = 1;
3546 uinfo->value.enumerated.items = 4;
3547 if (uinfo->value.enumerated.item >= 4)
3548 uinfo->value.enumerated.item = 3;
3549 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
3550 return 0;
3551}
3552
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003553static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
3554 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003555{
3556 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3557 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3558 unsigned int sel;
3559
3560 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
3561 ucontrol->value.enumerated.item[0] = sel & 3;
3562 return 0;
3563}
3564
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003565static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
3566 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003567{
3568 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3569 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3570 unsigned int sel;
3571
3572 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
3573 if (ucontrol->value.enumerated.item[0] != sel) {
3574 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003575 snd_hda_codec_write_cache(codec, nid, 0,
3576 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003577 return 1;
3578 }
3579 return 0;
3580}
3581
3582#define PIN_CTL_TEST(xname,nid) { \
3583 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3584 .name = xname, \
3585 .info = alc_test_pin_ctl_info, \
3586 .get = alc_test_pin_ctl_get, \
3587 .put = alc_test_pin_ctl_put, \
3588 .private_value = nid \
3589 }
3590
3591#define PIN_SRC_TEST(xname,nid) { \
3592 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3593 .name = xname, \
3594 .info = alc_test_pin_src_info, \
3595 .get = alc_test_pin_src_get, \
3596 .put = alc_test_pin_src_put, \
3597 .private_value = nid \
3598 }
3599
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003600static struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003601 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3602 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3603 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
3604 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003605 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
3606 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
3607 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
3608 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003609 PIN_CTL_TEST("Front Pin Mode", 0x14),
3610 PIN_CTL_TEST("Surround Pin Mode", 0x15),
3611 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
3612 PIN_CTL_TEST("Side Pin Mode", 0x17),
3613 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
3614 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
3615 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
3616 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
3617 PIN_SRC_TEST("In-1 Pin Source", 0x18),
3618 PIN_SRC_TEST("In-2 Pin Source", 0x19),
3619 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
3620 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
3621 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
3622 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
3623 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
3624 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
3625 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
3626 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
3627 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
3628 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
3629 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
3630 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003631 {
3632 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3633 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01003634 .info = alc_ch_mode_info,
3635 .get = alc_ch_mode_get,
3636 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003637 },
3638 { } /* end */
3639};
3640
3641static struct hda_verb alc880_test_init_verbs[] = {
3642 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02003643 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3644 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3645 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3646 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3647 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3648 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3649 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3650 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003651 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02003652 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3653 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3654 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3655 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003656 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003657 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3658 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3659 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3660 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003661 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003662 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3663 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3664 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3665 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003666 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02003667 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3668 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02003669 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3670 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3671 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003672 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02003673 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3674 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3675 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3676 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003677 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02003678 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003679 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003680 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003681 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003682 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003683 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003684 /* Analog input/passthru */
3685 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3686 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3687 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3688 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3689 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003690 { }
3691};
3692#endif
3693
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694/*
3695 */
3696
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003697static const char *alc880_models[ALC880_MODEL_LAST] = {
3698 [ALC880_3ST] = "3stack",
3699 [ALC880_TCL_S700] = "tcl",
3700 [ALC880_3ST_DIG] = "3stack-digout",
3701 [ALC880_CLEVO] = "clevo",
3702 [ALC880_5ST] = "5stack",
3703 [ALC880_5ST_DIG] = "5stack-digout",
3704 [ALC880_W810] = "w810",
3705 [ALC880_Z71V] = "z71v",
3706 [ALC880_6ST] = "6stack",
3707 [ALC880_6ST_DIG] = "6stack-digout",
3708 [ALC880_ASUS] = "asus",
3709 [ALC880_ASUS_W1V] = "asus-w1v",
3710 [ALC880_ASUS_DIG] = "asus-dig",
3711 [ALC880_ASUS_DIG2] = "asus-dig2",
3712 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003713 [ALC880_UNIWILL_P53] = "uniwill-p53",
3714 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003715 [ALC880_F1734] = "F1734",
3716 [ALC880_LG] = "lg",
3717 [ALC880_LG_LW] = "lg-lw",
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003718 [ALC880_MEDION_RIM] = "medion",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003719#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003720 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003721#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003722 [ALC880_AUTO] = "auto",
3723};
3724
3725static struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003726 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003727 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
3728 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
3729 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
3730 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
3731 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
3732 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
3733 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
3734 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003735 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
3736 SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003737 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
3738 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
3739 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
3740 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
3741 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
3742 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
3743 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
3744 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
3745 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
3746 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Travis Place186c3112008-05-20 11:54:41 +02003747 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003748 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
3749 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
3750 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaidea0a502009-02-09 17:14:52 +01003751 SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003752 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003753 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
3754 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003755 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
3756 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003757 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
3758 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
3759 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
3760 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003761 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
3762 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003763 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003764 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003765 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003766 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003767 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
3768 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003769 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003770 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003771 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003772 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003773 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Travis Place1d116042008-06-23 11:42:30 +02003774 SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003775 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003776 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003777 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003778 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
3779 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003780 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003781 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
3782 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
3783 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
3784 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003785 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
3786 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003787 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003788 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003789 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
3790 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003791 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
3792 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
3793 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +01003794 /* default Intel */
3795 SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003796 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
3797 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798 {}
3799};
3800
Takashi Iwai16ded522005-06-10 19:58:24 +02003801/*
Kailang Yangdf694da2005-12-05 19:42:22 +01003802 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02003803 */
Takashi Iwai16ded522005-06-10 19:58:24 +02003804static struct alc_config_preset alc880_presets[] = {
3805 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003806 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003807 .init_verbs = { alc880_volume_init_verbs,
3808 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003809 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02003810 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003811 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3812 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003813 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003814 .input_mux = &alc880_capture_source,
3815 },
3816 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003817 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003818 .init_verbs = { alc880_volume_init_verbs,
3819 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003820 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02003821 .dac_nids = alc880_dac_nids,
3822 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003823 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3824 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003825 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003826 .input_mux = &alc880_capture_source,
3827 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003828 [ALC880_TCL_S700] = {
3829 .mixers = { alc880_tcl_s700_mixer },
3830 .init_verbs = { alc880_volume_init_verbs,
3831 alc880_pin_tcl_S700_init_verbs,
3832 alc880_gpio2_init_verbs },
3833 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3834 .dac_nids = alc880_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01003835 .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */
3836 .num_adc_nids = 1, /* single ADC */
Kailang Yangdf694da2005-12-05 19:42:22 +01003837 .hp_nid = 0x03,
3838 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3839 .channel_mode = alc880_2_jack_modes,
3840 .input_mux = &alc880_capture_source,
3841 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003842 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003843 .mixers = { alc880_three_stack_mixer,
3844 alc880_five_stack_mixer},
3845 .init_verbs = { alc880_volume_init_verbs,
3846 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003847 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3848 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003849 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
3850 .channel_mode = alc880_fivestack_modes,
3851 .input_mux = &alc880_capture_source,
3852 },
3853 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003854 .mixers = { alc880_three_stack_mixer,
3855 alc880_five_stack_mixer },
3856 .init_verbs = { alc880_volume_init_verbs,
3857 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003858 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3859 .dac_nids = alc880_dac_nids,
3860 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003861 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
3862 .channel_mode = alc880_fivestack_modes,
3863 .input_mux = &alc880_capture_source,
3864 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003865 [ALC880_6ST] = {
3866 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003867 .init_verbs = { alc880_volume_init_verbs,
3868 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003869 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3870 .dac_nids = alc880_6st_dac_nids,
3871 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3872 .channel_mode = alc880_sixstack_modes,
3873 .input_mux = &alc880_6stack_capture_source,
3874 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003875 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003876 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003877 .init_verbs = { alc880_volume_init_verbs,
3878 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003879 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3880 .dac_nids = alc880_6st_dac_nids,
3881 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003882 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3883 .channel_mode = alc880_sixstack_modes,
3884 .input_mux = &alc880_6stack_capture_source,
3885 },
3886 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003887 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003888 .init_verbs = { alc880_volume_init_verbs,
3889 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003890 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003891 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
3892 .dac_nids = alc880_w810_dac_nids,
3893 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003894 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
3895 .channel_mode = alc880_w810_modes,
3896 .input_mux = &alc880_capture_source,
3897 },
3898 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003899 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003900 .init_verbs = { alc880_volume_init_verbs,
3901 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003902 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
3903 .dac_nids = alc880_z71v_dac_nids,
3904 .dig_out_nid = ALC880_DIGOUT_NID,
3905 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003906 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3907 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02003908 .input_mux = &alc880_capture_source,
3909 },
3910 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003911 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003912 .init_verbs = { alc880_volume_init_verbs,
3913 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003914 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
3915 .dac_nids = alc880_f1734_dac_nids,
3916 .hp_nid = 0x02,
3917 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3918 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01003919 .input_mux = &alc880_f1734_capture_source,
3920 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003921 .init_hook = alc880_uniwill_p53_init_hook,
Takashi Iwai16ded522005-06-10 19:58:24 +02003922 },
3923 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003924 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003925 .init_verbs = { alc880_volume_init_verbs,
3926 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003927 alc880_gpio1_init_verbs },
3928 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3929 .dac_nids = alc880_asus_dac_nids,
3930 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3931 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003932 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003933 .input_mux = &alc880_capture_source,
3934 },
3935 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003936 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003937 .init_verbs = { alc880_volume_init_verbs,
3938 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003939 alc880_gpio1_init_verbs },
3940 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3941 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003942 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003943 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3944 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003945 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003946 .input_mux = &alc880_capture_source,
3947 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003948 [ALC880_ASUS_DIG2] = {
3949 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003950 .init_verbs = { alc880_volume_init_verbs,
3951 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01003952 alc880_gpio2_init_verbs }, /* use GPIO2 */
3953 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3954 .dac_nids = alc880_asus_dac_nids,
3955 .dig_out_nid = ALC880_DIGOUT_NID,
3956 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3957 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003958 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003959 .input_mux = &alc880_capture_source,
3960 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003961 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003962 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003963 .init_verbs = { alc880_volume_init_verbs,
3964 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003965 alc880_gpio1_init_verbs },
3966 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3967 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003968 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003969 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3970 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003971 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003972 .input_mux = &alc880_capture_source,
3973 },
3974 [ALC880_UNIWILL_DIG] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003975 .mixers = { alc880_asus_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02003976 .init_verbs = { alc880_volume_init_verbs,
3977 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003978 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3979 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003980 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003981 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3982 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003983 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003984 .input_mux = &alc880_capture_source,
3985 },
Kailang Yangccc656c2006-10-17 12:32:26 +02003986 [ALC880_UNIWILL] = {
3987 .mixers = { alc880_uniwill_mixer },
3988 .init_verbs = { alc880_volume_init_verbs,
3989 alc880_uniwill_init_verbs },
3990 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3991 .dac_nids = alc880_asus_dac_nids,
3992 .dig_out_nid = ALC880_DIGOUT_NID,
3993 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3994 .channel_mode = alc880_threestack_modes,
3995 .need_dac_fix = 1,
3996 .input_mux = &alc880_capture_source,
3997 .unsol_event = alc880_uniwill_unsol_event,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003998 .init_hook = alc880_uniwill_init_hook,
Kailang Yangccc656c2006-10-17 12:32:26 +02003999 },
4000 [ALC880_UNIWILL_P53] = {
4001 .mixers = { alc880_uniwill_p53_mixer },
4002 .init_verbs = { alc880_volume_init_verbs,
4003 alc880_uniwill_p53_init_verbs },
4004 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4005 .dac_nids = alc880_asus_dac_nids,
4006 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004007 .channel_mode = alc880_threestack_modes,
4008 .input_mux = &alc880_capture_source,
4009 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004010 .init_hook = alc880_uniwill_p53_init_hook,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004011 },
4012 [ALC880_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004013 .mixers = { alc880_fujitsu_mixer },
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004014 .init_verbs = { alc880_volume_init_verbs,
4015 alc880_uniwill_p53_init_verbs,
4016 alc880_beep_init_verbs },
4017 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4018 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02004019 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004020 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4021 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02004022 .input_mux = &alc880_capture_source,
4023 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004024 .init_hook = alc880_uniwill_p53_init_hook,
Kailang Yangccc656c2006-10-17 12:32:26 +02004025 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004026 [ALC880_CLEVO] = {
4027 .mixers = { alc880_three_stack_mixer },
4028 .init_verbs = { alc880_volume_init_verbs,
4029 alc880_pin_clevo_init_verbs },
4030 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4031 .dac_nids = alc880_dac_nids,
4032 .hp_nid = 0x03,
4033 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4034 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004035 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01004036 .input_mux = &alc880_capture_source,
4037 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004038 [ALC880_LG] = {
4039 .mixers = { alc880_lg_mixer },
4040 .init_verbs = { alc880_volume_init_verbs,
4041 alc880_lg_init_verbs },
4042 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
4043 .dac_nids = alc880_lg_dac_nids,
4044 .dig_out_nid = ALC880_DIGOUT_NID,
4045 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
4046 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004047 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004048 .input_mux = &alc880_lg_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004049 .unsol_event = alc_automute_amp_unsol_event,
4050 .init_hook = alc880_lg_init_hook,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004051#ifdef CONFIG_SND_HDA_POWER_SAVE
4052 .loopbacks = alc880_lg_loopbacks,
4053#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004054 },
Takashi Iwaid6815182006-03-23 16:06:23 +01004055 [ALC880_LG_LW] = {
4056 .mixers = { alc880_lg_lw_mixer },
4057 .init_verbs = { alc880_volume_init_verbs,
4058 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004059 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01004060 .dac_nids = alc880_dac_nids,
4061 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004062 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
4063 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01004064 .input_mux = &alc880_lg_lw_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004065 .unsol_event = alc_automute_amp_unsol_event,
4066 .init_hook = alc880_lg_lw_init_hook,
Takashi Iwaid6815182006-03-23 16:06:23 +01004067 },
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004068 [ALC880_MEDION_RIM] = {
4069 .mixers = { alc880_medion_rim_mixer },
4070 .init_verbs = { alc880_volume_init_verbs,
4071 alc880_medion_rim_init_verbs,
4072 alc_gpio2_init_verbs },
4073 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4074 .dac_nids = alc880_dac_nids,
4075 .dig_out_nid = ALC880_DIGOUT_NID,
4076 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4077 .channel_mode = alc880_2_jack_modes,
4078 .input_mux = &alc880_medion_rim_capture_source,
4079 .unsol_event = alc880_medion_rim_unsol_event,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004080 .init_hook = alc880_medion_rim_init_hook,
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004081 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004082#ifdef CONFIG_SND_DEBUG
4083 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004084 .mixers = { alc880_test_mixer },
4085 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004086 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
4087 .dac_nids = alc880_test_dac_nids,
4088 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004089 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
4090 .channel_mode = alc880_test_modes,
4091 .input_mux = &alc880_test_capture_source,
4092 },
4093#endif
4094};
4095
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004096/*
4097 * Automatic parse of I/O pins from the BIOS configuration
4098 */
4099
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004100enum {
4101 ALC_CTL_WIDGET_VOL,
4102 ALC_CTL_WIDGET_MUTE,
4103 ALC_CTL_BIND_MUTE,
4104};
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004105static struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004106 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
4107 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01004108 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004109};
4110
4111/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004112static int add_control(struct alc_spec *spec, int type, const char *name,
4113 unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004114{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004115 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004116
Takashi Iwai603c4012008-07-30 15:01:44 +02004117 snd_array_init(&spec->kctls, sizeof(*knew), 32);
4118 knew = snd_array_new(&spec->kctls);
4119 if (!knew)
4120 return -ENOMEM;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004121 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07004122 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004123 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004124 return -ENOMEM;
4125 knew->private_value = val;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004126 return 0;
4127}
4128
4129#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
4130#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
4131#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
4132#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
4133#define alc880_is_input_pin(nid) ((nid) >= 0x18)
4134#define alc880_input_pin_idx(nid) ((nid) - 0x18)
4135#define alc880_idx_to_dac(nid) ((nid) + 0x02)
4136#define alc880_dac_to_idx(nid) ((nid) - 0x02)
4137#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
4138#define alc880_idx_to_selector(nid) ((nid) + 0x10)
4139#define ALC880_PIN_CD_NID 0x1c
4140
4141/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004142static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
4143 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004144{
4145 hda_nid_t nid;
4146 int assigned[4];
4147 int i, j;
4148
4149 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02004150 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004151
4152 /* check the pins hardwired to audio widget */
4153 for (i = 0; i < cfg->line_outs; i++) {
4154 nid = cfg->line_out_pins[i];
4155 if (alc880_is_fixed_pin(nid)) {
4156 int idx = alc880_fixed_pin_idx(nid);
Libin Yang5014f192005-11-23 15:48:36 +01004157 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004158 assigned[idx] = 1;
4159 }
4160 }
4161 /* left pins can be connect to any audio widget */
4162 for (i = 0; i < cfg->line_outs; i++) {
4163 nid = cfg->line_out_pins[i];
4164 if (alc880_is_fixed_pin(nid))
4165 continue;
4166 /* search for an empty channel */
4167 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004168 if (!assigned[j]) {
4169 spec->multiout.dac_nids[i] =
4170 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004171 assigned[j] = 1;
4172 break;
4173 }
4174 }
4175 }
4176 spec->multiout.num_dacs = cfg->line_outs;
4177 return 0;
4178}
4179
4180/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01004181static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
4182 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004183{
4184 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004185 static const char *chname[4] = {
4186 "Front", "Surround", NULL /*CLFE*/, "Side"
4187 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004188 hda_nid_t nid;
4189 int i, err;
4190
4191 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004192 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004193 continue;
4194 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
4195 if (i == 2) {
4196 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004197 err = add_control(spec, ALC_CTL_WIDGET_VOL,
4198 "Center Playback Volume",
4199 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
4200 HDA_OUTPUT));
4201 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004202 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004203 err = add_control(spec, ALC_CTL_WIDGET_VOL,
4204 "LFE Playback Volume",
4205 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
4206 HDA_OUTPUT));
4207 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004208 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004209 err = add_control(spec, ALC_CTL_BIND_MUTE,
4210 "Center Playback Switch",
4211 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
4212 HDA_INPUT));
4213 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004214 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004215 err = add_control(spec, ALC_CTL_BIND_MUTE,
4216 "LFE Playback Switch",
4217 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
4218 HDA_INPUT));
4219 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004220 return err;
4221 } else {
4222 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004223 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
4224 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
4225 HDA_OUTPUT));
4226 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004227 return err;
4228 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004229 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
4230 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
4231 HDA_INPUT));
4232 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004233 return err;
4234 }
4235 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004236 return 0;
4237}
4238
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004239/* add playback controls for speaker and HP outputs */
4240static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
4241 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004242{
4243 hda_nid_t nid;
4244 int err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004245 char name[32];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004246
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004247 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004248 return 0;
4249
4250 if (alc880_is_fixed_pin(pin)) {
4251 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01004252 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004253 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004254 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01004255 else
4256 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004257 /* control HP volume/switch on the output mixer amp */
4258 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004259 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004260 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
4261 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
4262 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004263 return err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004264 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004265 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
4266 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
4267 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004268 return err;
4269 } else if (alc880_is_multi_pin(pin)) {
4270 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004271 /* we have only a switch on HP-out PIN */
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004272 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004273 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
4274 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
4275 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004276 return err;
4277 }
4278 return 0;
4279}
4280
4281/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004282static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
4283 const char *ctlname,
Kailang Yangdf694da2005-12-05 19:42:22 +01004284 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004285{
4286 char name[32];
Kailang Yangdf694da2005-12-05 19:42:22 +01004287 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004288
4289 sprintf(name, "%s Playback Volume", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004290 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
4291 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
4292 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004293 return err;
4294 sprintf(name, "%s Playback Switch", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004295 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
4296 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
4297 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004298 return err;
4299 return 0;
4300}
4301
4302/* create playback/capture controls for input pins */
Kailang Yangdf694da2005-12-05 19:42:22 +01004303static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec,
4304 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004305{
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02004306 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004307 int i, err, idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004308
4309 for (i = 0; i < AUTO_PIN_LAST; i++) {
4310 if (alc880_is_input_pin(cfg->input_pins[i])) {
Kailang Yangdf694da2005-12-05 19:42:22 +01004311 idx = alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwai4a471b72005-12-07 13:56:29 +01004312 err = new_analog_input(spec, cfg->input_pins[i],
4313 auto_pin_cfg_labels[i],
Kailang Yangdf694da2005-12-05 19:42:22 +01004314 idx, 0x0b);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004315 if (err < 0)
4316 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004317 imux->items[imux->num_items].label =
4318 auto_pin_cfg_labels[i];
4319 imux->items[imux->num_items].index =
4320 alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004321 imux->num_items++;
4322 }
4323 }
4324 return 0;
4325}
4326
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004327static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
4328 unsigned int pin_type)
4329{
4330 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4331 pin_type);
4332 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01004333 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
4334 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004335}
4336
Kailang Yangdf694da2005-12-05 19:42:22 +01004337static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
4338 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004339 int dac_idx)
4340{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004341 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004342 /* need the manual connection? */
4343 if (alc880_is_multi_pin(nid)) {
4344 struct alc_spec *spec = codec->spec;
4345 int idx = alc880_multi_pin_idx(nid);
4346 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
4347 AC_VERB_SET_CONNECT_SEL,
4348 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
4349 }
4350}
4351
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004352static int get_pin_type(int line_out_type)
4353{
4354 if (line_out_type == AUTO_PIN_HP_OUT)
4355 return PIN_HP;
4356 else
4357 return PIN_OUT;
4358}
4359
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004360static void alc880_auto_init_multi_out(struct hda_codec *codec)
4361{
4362 struct alc_spec *spec = codec->spec;
4363 int i;
Kailang Yangea1fb292008-08-26 12:58:38 +02004364
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004365 for (i = 0; i < spec->autocfg.line_outs; i++) {
4366 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004367 int pin_type = get_pin_type(spec->autocfg.line_out_type);
4368 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004369 }
4370}
4371
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004372static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004373{
4374 struct alc_spec *spec = codec->spec;
4375 hda_nid_t pin;
4376
Takashi Iwai82bc9552006-03-21 11:24:42 +01004377 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004378 if (pin) /* connect to front */
4379 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004380 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004381 if (pin) /* connect to front */
4382 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
4383}
4384
4385static void alc880_auto_init_analog_input(struct hda_codec *codec)
4386{
4387 struct alc_spec *spec = codec->spec;
4388 int i;
4389
4390 for (i = 0; i < AUTO_PIN_LAST; i++) {
4391 hda_nid_t nid = spec->autocfg.input_pins[i];
4392 if (alc880_is_input_pin(nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +01004393 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +01004394 if (nid != ALC880_PIN_CD_NID &&
4395 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004396 snd_hda_codec_write(codec, nid, 0,
4397 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004398 AMP_OUT_MUTE);
4399 }
4400 }
4401}
4402
4403/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004404/* return 1 if successful, 0 if the proper config is not found,
4405 * or a negative error code
4406 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004407static int alc880_parse_auto_config(struct hda_codec *codec)
4408{
4409 struct alc_spec *spec = codec->spec;
Takashi Iwai6a05ac42009-02-13 11:19:09 +01004410 int i, err;
Kailang Yangdf694da2005-12-05 19:42:22 +01004411 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004412
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004413 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
4414 alc880_ignore);
4415 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004416 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004417 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004418 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01004419
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004420 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
4421 if (err < 0)
4422 return err;
4423 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
4424 if (err < 0)
4425 return err;
4426 err = alc880_auto_create_extra_out(spec,
4427 spec->autocfg.speaker_pins[0],
4428 "Speaker");
4429 if (err < 0)
4430 return err;
4431 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
4432 "Headphone");
4433 if (err < 0)
4434 return err;
4435 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
4436 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004437 return err;
4438
4439 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
4440
Takashi Iwai6a05ac42009-02-13 11:19:09 +01004441 /* check multiple SPDIF-out (for recent codecs) */
4442 for (i = 0; i < spec->autocfg.dig_outs; i++) {
4443 hda_nid_t dig_nid;
4444 err = snd_hda_get_connections(codec,
4445 spec->autocfg.dig_out_pins[i],
4446 &dig_nid, 1);
4447 if (err < 0)
4448 continue;
4449 if (!i)
4450 spec->multiout.dig_out_nid = dig_nid;
4451 else {
4452 spec->multiout.slave_dig_outs = spec->slave_dig_outs;
4453 spec->slave_dig_outs[i - 1] = dig_nid;
4454 if (i == ARRAY_SIZE(spec->slave_dig_outs) - 1)
4455 break;
4456 }
4457 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004458 if (spec->autocfg.dig_in_pin)
4459 spec->dig_in_nid = ALC880_DIGIN_NID;
4460
Takashi Iwai603c4012008-07-30 15:01:44 +02004461 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01004462 add_mixer(spec, spec->kctls.list);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004463
Takashi Iwaid88897e2008-10-31 15:01:37 +01004464 add_verb(spec, alc880_volume_init_verbs);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004465
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004466 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02004467 spec->input_mux = &spec->private_imux[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004468
Takashi Iwai4a79ba342009-04-22 16:31:35 +02004469 alc_ssid_check(codec, 0x15, 0x1b, 0x14);
4470
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004471 return 1;
4472}
4473
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004474/* additional initialization for auto-configuration model */
4475static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004476{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004477 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004478 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004479 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004480 alc880_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004481 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02004482 alc_inithook(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004483}
4484
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004485static void set_capture_mixer(struct alc_spec *spec)
4486{
Takashi Iwaia23b6882009-03-23 15:21:36 +01004487 static struct snd_kcontrol_new *caps[2][3] = {
4488 { alc_capture_mixer_nosrc1,
4489 alc_capture_mixer_nosrc2,
4490 alc_capture_mixer_nosrc3 },
4491 { alc_capture_mixer1,
4492 alc_capture_mixer2,
4493 alc_capture_mixer3 },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004494 };
Takashi Iwaia23b6882009-03-23 15:21:36 +01004495 if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
4496 int mux;
4497 if (spec->input_mux && spec->input_mux->num_items > 1)
4498 mux = 1;
4499 else
4500 mux = 0;
4501 spec->cap_mixer = caps[mux][spec->num_adc_nids - 1];
4502 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004503}
4504
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004505#define set_beep_amp(spec, nid, idx, dir) \
4506 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
4507
4508/*
4509 * OK, here we have finally the patch for ALC880
4510 */
4511
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512static int patch_alc880(struct hda_codec *codec)
4513{
4514 struct alc_spec *spec;
4515 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01004516 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517
Takashi Iwaie560d8d2005-09-09 14:21:46 +02004518 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004519 if (spec == NULL)
4520 return -ENOMEM;
4521
4522 codec->spec = spec;
4523
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004524 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
4525 alc880_models,
4526 alc880_cfg_tbl);
4527 if (board_config < 0) {
Takashi Iwai6c627f32009-05-18 12:33:36 +02004528 printk(KERN_INFO "hda_codec: Unknown model for %s, "
4529 "trying auto-probe from BIOS...\n", codec->chip_name);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004530 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531 }
4532
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004533 if (board_config == ALC880_AUTO) {
4534 /* automatic parse from the BIOS config */
4535 err = alc880_parse_auto_config(codec);
4536 if (err < 0) {
4537 alc_free(codec);
4538 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004539 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004540 printk(KERN_INFO
4541 "hda_codec: Cannot set up configuration "
4542 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004543 board_config = ALC880_3ST;
4544 }
4545 }
4546
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09004547 err = snd_hda_attach_beep_device(codec, 0x1);
4548 if (err < 0) {
4549 alc_free(codec);
4550 return err;
4551 }
4552
Kailang Yangdf694da2005-12-05 19:42:22 +01004553 if (board_config != ALC880_AUTO)
4554 setup_preset(spec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556 spec->stream_analog_playback = &alc880_pcm_analog_playback;
4557 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01004558 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004559
Linus Torvalds1da177e2005-04-16 15:20:36 -07004560 spec->stream_digital_playback = &alc880_pcm_digital_playback;
4561 spec->stream_digital_capture = &alc880_pcm_digital_capture;
4562
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004563 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004564 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01004565 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004566 /* get type */
4567 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004568 if (wcap != AC_WID_AUD_IN) {
4569 spec->adc_nids = alc880_adc_nids_alt;
4570 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004571 } else {
4572 spec->adc_nids = alc880_adc_nids;
4573 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004574 }
4575 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004576 set_capture_mixer(spec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004577 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578
Takashi Iwai2134ea42008-01-10 16:53:55 +01004579 spec->vmaster_nid = 0x0c;
4580
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004582 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004583 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02004584#ifdef CONFIG_SND_HDA_POWER_SAVE
4585 if (!spec->loopback.amplist)
4586 spec->loopback.amplist = alc880_loopbacks;
4587#endif
Takashi Iwaidaead532008-11-28 12:55:36 +01004588 codec->proc_widget_hook = print_realtek_coef;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589
4590 return 0;
4591}
4592
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004593
Linus Torvalds1da177e2005-04-16 15:20:36 -07004594/*
4595 * ALC260 support
4596 */
4597
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004598static hda_nid_t alc260_dac_nids[1] = {
4599 /* front */
4600 0x02,
4601};
4602
4603static hda_nid_t alc260_adc_nids[1] = {
4604 /* ADC0 */
4605 0x04,
4606};
4607
Kailang Yangdf694da2005-12-05 19:42:22 +01004608static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004609 /* ADC1 */
4610 0x05,
4611};
4612
Jonathan Woithed57fdac2006-02-28 11:38:35 +01004613/* NIDs used when simultaneous access to both ADCs makes sense. Note that
4614 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
4615 */
4616static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004617 /* ADC0, ADC1 */
4618 0x04, 0x05
4619};
4620
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004621#define ALC260_DIGOUT_NID 0x03
4622#define ALC260_DIGIN_NID 0x06
4623
4624static struct hda_input_mux alc260_capture_source = {
4625 .num_items = 4,
4626 .items = {
4627 { "Mic", 0x0 },
4628 { "Front Mic", 0x1 },
4629 { "Line", 0x2 },
4630 { "CD", 0x4 },
4631 },
4632};
4633
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01004634/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004635 * headphone jack and the internal CD lines since these are the only pins at
4636 * which audio can appear. For flexibility, also allow the option of
4637 * recording the mixer output on the second ADC (ADC0 doesn't have a
4638 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004639 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004640static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
4641 {
4642 .num_items = 3,
4643 .items = {
4644 { "Mic/Line", 0x0 },
4645 { "CD", 0x4 },
4646 { "Headphone", 0x2 },
4647 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004648 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004649 {
4650 .num_items = 4,
4651 .items = {
4652 { "Mic/Line", 0x0 },
4653 { "CD", 0x4 },
4654 { "Headphone", 0x2 },
4655 { "Mixer", 0x5 },
4656 },
4657 },
4658
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004659};
4660
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004661/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
4662 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004663 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004664static struct hda_input_mux alc260_acer_capture_sources[2] = {
4665 {
4666 .num_items = 4,
4667 .items = {
4668 { "Mic", 0x0 },
4669 { "Line", 0x2 },
4670 { "CD", 0x4 },
4671 { "Headphone", 0x5 },
4672 },
4673 },
4674 {
4675 .num_items = 5,
4676 .items = {
4677 { "Mic", 0x0 },
4678 { "Line", 0x2 },
4679 { "CD", 0x4 },
4680 { "Headphone", 0x6 },
4681 { "Mixer", 0x5 },
4682 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004683 },
4684};
Michael Schwingencc959482009-02-22 18:58:45 +01004685
4686/* Maxdata Favorit 100XS */
4687static struct hda_input_mux alc260_favorit100_capture_sources[2] = {
4688 {
4689 .num_items = 2,
4690 .items = {
4691 { "Line/Mic", 0x0 },
4692 { "CD", 0x4 },
4693 },
4694 },
4695 {
4696 .num_items = 3,
4697 .items = {
4698 { "Line/Mic", 0x0 },
4699 { "CD", 0x4 },
4700 { "Mixer", 0x5 },
4701 },
4702 },
4703};
4704
Linus Torvalds1da177e2005-04-16 15:20:36 -07004705/*
4706 * This is just place-holder, so there's something for alc_build_pcms to look
4707 * at when it calculates the maximum number of channels. ALC260 has no mixer
4708 * element which allows changing the channel mode, so the verb list is
4709 * never used.
4710 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01004711static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004712 { 2, NULL },
4713};
4714
Kailang Yangdf694da2005-12-05 19:42:22 +01004715
4716/* Mixer combinations
4717 *
4718 * basic: base_output + input + pc_beep + capture
4719 * HP: base_output + input + capture_alt
4720 * HP_3013: hp_3013 + input + capture
4721 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004722 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01004723 */
4724
4725static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02004726 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004727 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004728 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4729 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
4730 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4731 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4732 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004733};
Kailang Yangdf694da2005-12-05 19:42:22 +01004734
4735static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004736 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4737 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4738 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4739 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4740 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4741 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4742 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
4743 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004744 { } /* end */
4745};
4746
Takashi Iwaibec15c32008-01-28 18:16:30 +01004747/* update HP, line and mono out pins according to the master switch */
4748static void alc260_hp_master_update(struct hda_codec *codec,
4749 hda_nid_t hp, hda_nid_t line,
4750 hda_nid_t mono)
4751{
4752 struct alc_spec *spec = codec->spec;
4753 unsigned int val = spec->master_sw ? PIN_HP : 0;
4754 /* change HP and line-out pins */
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004755 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01004756 val);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004757 snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01004758 val);
4759 /* mono (speaker) depending on the HP jack sense */
4760 val = (val && !spec->jack_present) ? PIN_OUT : 0;
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004761 snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01004762 val);
4763}
4764
4765static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
4766 struct snd_ctl_elem_value *ucontrol)
4767{
4768 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4769 struct alc_spec *spec = codec->spec;
4770 *ucontrol->value.integer.value = spec->master_sw;
4771 return 0;
4772}
4773
4774static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
4775 struct snd_ctl_elem_value *ucontrol)
4776{
4777 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4778 struct alc_spec *spec = codec->spec;
4779 int val = !!*ucontrol->value.integer.value;
4780 hda_nid_t hp, line, mono;
4781
4782 if (val == spec->master_sw)
4783 return 0;
4784 spec->master_sw = val;
4785 hp = (kcontrol->private_value >> 16) & 0xff;
4786 line = (kcontrol->private_value >> 8) & 0xff;
4787 mono = kcontrol->private_value & 0xff;
4788 alc260_hp_master_update(codec, hp, line, mono);
4789 return 1;
4790}
4791
4792static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
4793 {
4794 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4795 .name = "Master Playback Switch",
4796 .info = snd_ctl_boolean_mono_info,
4797 .get = alc260_hp_master_sw_get,
4798 .put = alc260_hp_master_sw_put,
4799 .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
4800 },
4801 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4802 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
4803 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4804 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
4805 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
4806 HDA_OUTPUT),
4807 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4808 { } /* end */
4809};
4810
4811static struct hda_verb alc260_hp_unsol_verbs[] = {
4812 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4813 {},
4814};
4815
4816static void alc260_hp_automute(struct hda_codec *codec)
4817{
4818 struct alc_spec *spec = codec->spec;
4819 unsigned int present;
4820
4821 present = snd_hda_codec_read(codec, 0x10, 0,
4822 AC_VERB_GET_PIN_SENSE, 0);
4823 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
4824 alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
4825}
4826
4827static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
4828{
4829 if ((res >> 26) == ALC880_HP_EVENT)
4830 alc260_hp_automute(codec);
4831}
4832
Kailang Yangdf694da2005-12-05 19:42:22 +01004833static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01004834 {
4835 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4836 .name = "Master Playback Switch",
4837 .info = snd_ctl_boolean_mono_info,
4838 .get = alc260_hp_master_sw_get,
4839 .put = alc260_hp_master_sw_put,
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004840 .private_value = (0x15 << 16) | (0x10 << 8) | 0x11
Takashi Iwaibec15c32008-01-28 18:16:30 +01004841 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004842 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4843 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
4844 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
4845 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
4846 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4847 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01004848 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4849 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02004850 { } /* end */
4851};
4852
Kailang Yang3f878302008-08-26 13:02:23 +02004853static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
4854 .ops = &snd_hda_bind_vol,
4855 .values = {
4856 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
4857 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
4858 HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
4859 0
4860 },
4861};
4862
4863static struct hda_bind_ctls alc260_dc7600_bind_switch = {
4864 .ops = &snd_hda_bind_sw,
4865 .values = {
4866 HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
4867 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
4868 0
4869 },
4870};
4871
4872static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
4873 HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
4874 HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
4875 HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
4876 HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
4877 { } /* end */
4878};
4879
Takashi Iwaibec15c32008-01-28 18:16:30 +01004880static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
4881 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4882 {},
4883};
4884
4885static void alc260_hp_3013_automute(struct hda_codec *codec)
4886{
4887 struct alc_spec *spec = codec->spec;
4888 unsigned int present;
4889
4890 present = snd_hda_codec_read(codec, 0x15, 0,
4891 AC_VERB_GET_PIN_SENSE, 0);
4892 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004893 alc260_hp_master_update(codec, 0x15, 0x10, 0x11);
Takashi Iwaibec15c32008-01-28 18:16:30 +01004894}
4895
4896static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
4897 unsigned int res)
4898{
4899 if ((res >> 26) == ALC880_HP_EVENT)
4900 alc260_hp_3013_automute(codec);
4901}
4902
Kailang Yang3f878302008-08-26 13:02:23 +02004903static void alc260_hp_3012_automute(struct hda_codec *codec)
4904{
4905 unsigned int present, bits;
4906
4907 present = snd_hda_codec_read(codec, 0x10, 0,
4908 AC_VERB_GET_PIN_SENSE, 0) & AC_PINSENSE_PRESENCE;
4909
4910 bits = present ? 0 : PIN_OUT;
4911 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4912 bits);
4913 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4914 bits);
4915 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4916 bits);
4917}
4918
4919static void alc260_hp_3012_unsol_event(struct hda_codec *codec,
4920 unsigned int res)
4921{
4922 if ((res >> 26) == ALC880_HP_EVENT)
4923 alc260_hp_3012_automute(codec);
4924}
4925
4926/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004927 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
4928 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004929static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004930 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004931 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004932 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004933 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4934 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4935 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
4936 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004937 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004938 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4939 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004940 { } /* end */
4941};
4942
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004943/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
4944 * versions of the ALC260 don't act on requests to enable mic bias from NID
4945 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
4946 * datasheet doesn't mention this restriction. At this stage it's not clear
4947 * whether this behaviour is intentional or is a hardware bug in chip
4948 * revisions available in early 2006. Therefore for now allow the
4949 * "Headphone Jack Mode" control to span all choices, but if it turns out
4950 * that the lack of mic bias for this NID is intentional we could change the
4951 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
4952 *
4953 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
4954 * don't appear to make the mic bias available from the "line" jack, even
4955 * though the NID used for this jack (0x14) can supply it. The theory is
4956 * that perhaps Acer have included blocking capacitors between the ALC260
4957 * and the output jack. If this turns out to be the case for all such
4958 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
4959 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01004960 *
4961 * The C20x Tablet series have a mono internal speaker which is controlled
4962 * via the chip's Mono sum widget and pin complex, so include the necessary
4963 * controls for such models. On models without a "mono speaker" the control
4964 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004965 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004966static struct snd_kcontrol_new alc260_acer_mixer[] = {
4967 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4968 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004969 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004970 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01004971 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004972 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01004973 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004974 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4975 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4976 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4977 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4978 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4979 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4980 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4981 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004982 { } /* end */
4983};
4984
Michael Schwingencc959482009-02-22 18:58:45 +01004985/* Maxdata Favorit 100XS: one output and one input (0x12) jack
4986 */
4987static struct snd_kcontrol_new alc260_favorit100_mixer[] = {
4988 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4989 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
4990 ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
4991 HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4992 HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4993 ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4994 { } /* end */
4995};
4996
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004997/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
4998 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
4999 */
5000static struct snd_kcontrol_new alc260_will_mixer[] = {
5001 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5002 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
5003 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5004 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5005 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5006 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5007 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5008 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
5009 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5010 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005011 { } /* end */
5012};
5013
5014/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
5015 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
5016 */
5017static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
5018 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5019 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
5020 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5021 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5022 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5023 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
5024 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
5025 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5026 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5027 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
5028 { } /* end */
5029};
5030
Kailang Yangdf694da2005-12-05 19:42:22 +01005031/*
5032 * initialization verbs
5033 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005034static struct hda_verb alc260_init_verbs[] = {
5035 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005036 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005037 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005038 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005039 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005040 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005041 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005042 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005043 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02005044 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005045 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01005046 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02005048 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005049 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02005050 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005051 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02005052 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5053 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02005054 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005055 /* set connection select to line in (default select for this ADC) */
5056 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02005057 /* mute capture amp left and right */
5058 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5059 /* set connection select to line in (default select for this ADC) */
5060 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02005061 /* set vol=0 Line-Out mixer amp left and right */
5062 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5063 /* unmute pin widget amp left and right (no gain on this amp) */
5064 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5065 /* set vol=0 HP mixer amp left and right */
5066 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5067 /* unmute pin widget amp left and right (no gain on this amp) */
5068 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5069 /* set vol=0 Mono mixer amp left and right */
5070 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5071 /* unmute pin widget amp left and right (no gain on this amp) */
5072 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5073 /* unmute LINE-2 out pin */
5074 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005075 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
5076 * Line In 2 = 0x03
5077 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005078 /* mute analog inputs */
5079 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5080 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5081 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5082 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5083 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005084 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005085 /* mute Front out path */
5086 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5087 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5088 /* mute Headphone out path */
5089 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5090 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5091 /* mute Mono out path */
5092 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5093 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005094 { }
5095};
5096
Takashi Iwai474167d2006-05-17 17:17:43 +02005097#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01005098static struct hda_verb alc260_hp_init_verbs[] = {
5099 /* Headphone and output */
5100 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
5101 /* mono output */
5102 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5103 /* Mic1 (rear panel) pin widget for input and vref at 80% */
5104 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5105 /* Mic2 (front panel) pin widget for input and vref at 80% */
5106 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5107 /* Line In pin widget for input */
5108 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5109 /* Line-2 pin widget for output */
5110 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5111 /* CD pin widget for input */
5112 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5113 /* unmute amp left and right */
5114 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
5115 /* set connection select to line in (default select for this ADC) */
5116 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
5117 /* unmute Line-Out mixer amp left and right (volume = 0) */
5118 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5119 /* mute pin widget amp left and right (no gain on this amp) */
5120 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
5121 /* unmute HP mixer amp left and right (volume = 0) */
5122 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5123 /* mute pin widget amp left and right (no gain on this amp) */
5124 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005125 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
5126 * Line In 2 = 0x03
5127 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005128 /* mute analog inputs */
5129 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5130 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5131 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5132 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5133 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005134 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
5135 /* Unmute Front out path */
5136 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5137 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5138 /* Unmute Headphone out path */
5139 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5140 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5141 /* Unmute Mono out path */
5142 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5143 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5144 { }
5145};
Takashi Iwai474167d2006-05-17 17:17:43 +02005146#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01005147
5148static struct hda_verb alc260_hp_3013_init_verbs[] = {
5149 /* Line out and output */
5150 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5151 /* mono output */
5152 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5153 /* Mic1 (rear panel) pin widget for input and vref at 80% */
5154 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5155 /* Mic2 (front panel) pin widget for input and vref at 80% */
5156 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5157 /* Line In pin widget for input */
5158 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5159 /* Headphone pin widget for output */
5160 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
5161 /* CD pin widget for input */
5162 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5163 /* unmute amp left and right */
5164 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
5165 /* set connection select to line in (default select for this ADC) */
5166 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
5167 /* unmute Line-Out mixer amp left and right (volume = 0) */
5168 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5169 /* mute pin widget amp left and right (no gain on this amp) */
5170 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
5171 /* unmute HP mixer amp left and right (volume = 0) */
5172 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5173 /* mute pin widget amp left and right (no gain on this amp) */
5174 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005175 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
5176 * Line In 2 = 0x03
5177 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005178 /* mute analog inputs */
5179 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5180 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5181 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5182 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5183 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005184 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
5185 /* Unmute Front out path */
5186 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5187 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5188 /* Unmute Headphone out path */
5189 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5190 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5191 /* Unmute Mono out path */
5192 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5193 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5194 { }
5195};
5196
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005197/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005198 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
5199 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005200 */
5201static struct hda_verb alc260_fujitsu_init_verbs[] = {
5202 /* Disable all GPIOs */
5203 {0x01, AC_VERB_SET_GPIO_MASK, 0},
5204 /* Internal speaker is connected to headphone pin */
5205 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5206 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
5207 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005208 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
5209 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
5210 /* Ensure all other unused pins are disabled and muted. */
5211 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5212 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005213 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005214 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005215 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005216 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5217 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5218 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005219
Jonathan Woithef7ace402006-02-28 11:46:14 +01005220 /* Disable digital (SPDIF) pins */
5221 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5222 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005223
Kailang Yangea1fb292008-08-26 12:58:38 +02005224 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
Jonathan Woithef7ace402006-02-28 11:46:14 +01005225 * when acting as an output.
5226 */
5227 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5228
5229 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01005230 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5231 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5232 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5233 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5234 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5235 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5236 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5237 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5238 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005239
Jonathan Woithef7ace402006-02-28 11:46:14 +01005240 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
5241 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5242 /* Unmute Line1 pin widget output buffer since it starts as an output.
5243 * If the pin mode is changed by the user the pin mode control will
5244 * take care of enabling the pin's input/output buffers as needed.
5245 * Therefore there's no need to enable the input buffer at this
5246 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01005247 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01005248 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +02005249 /* Unmute input buffer of pin widget used for Line-in (no equiv
Jonathan Woithecdcd9262006-02-28 11:36:42 +01005250 * mixer ctrl)
5251 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01005252 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005253
Jonathan Woithef7ace402006-02-28 11:46:14 +01005254 /* Mute capture amp left and right */
5255 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02005256 /* Set ADC connection select to match default mixer setting - line
Jonathan Woithef7ace402006-02-28 11:46:14 +01005257 * in (on mic1 pin)
5258 */
5259 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005260
Jonathan Woithef7ace402006-02-28 11:46:14 +01005261 /* Do the same for the second ADC: mute capture input amp and
5262 * set ADC connection to line in (on mic1 pin)
5263 */
5264 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5265 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005266
Jonathan Woithef7ace402006-02-28 11:46:14 +01005267 /* Mute all inputs to mixer widget (even unconnected ones) */
5268 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5269 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5270 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5271 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5272 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5273 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5274 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5275 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01005276
5277 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005278};
5279
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005280/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
5281 * similar laptops (adapted from Fujitsu init verbs).
5282 */
5283static struct hda_verb alc260_acer_init_verbs[] = {
5284 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
5285 * the headphone jack. Turn this on and rely on the standard mute
5286 * methods whenever the user wants to turn these outputs off.
5287 */
5288 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
5289 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
5290 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
5291 /* Internal speaker/Headphone jack is connected to Line-out pin */
5292 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5293 /* Internal microphone/Mic jack is connected to Mic1 pin */
5294 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
5295 /* Line In jack is connected to Line1 pin */
5296 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01005297 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
5298 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005299 /* Ensure all other unused pins are disabled and muted. */
5300 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5301 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005302 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5303 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5304 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5305 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5306 /* Disable digital (SPDIF) pins */
5307 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5308 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
5309
Kailang Yangea1fb292008-08-26 12:58:38 +02005310 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005311 * bus when acting as outputs.
5312 */
5313 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
5314 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5315
5316 /* Start with output sum widgets muted and their output gains at min */
5317 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5318 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5319 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5320 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5321 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5322 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5323 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5324 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5325 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5326
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005327 /* Unmute Line-out pin widget amp left and right
5328 * (no equiv mixer ctrl)
5329 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005330 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01005331 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
5332 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005333 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
5334 * inputs. If the pin mode is changed by the user the pin mode control
5335 * will take care of enabling the pin's input/output buffers as needed.
5336 * Therefore there's no need to enable the input buffer at this
5337 * stage.
5338 */
5339 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5340 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5341
5342 /* Mute capture amp left and right */
5343 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5344 /* Set ADC connection select to match default mixer setting - mic
5345 * (on mic1 pin)
5346 */
5347 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5348
5349 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005350 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005351 */
5352 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005353 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005354
5355 /* Mute all inputs to mixer widget (even unconnected ones) */
5356 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5357 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5358 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5359 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5360 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5361 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5362 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5363 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
5364
5365 { }
5366};
5367
Michael Schwingencc959482009-02-22 18:58:45 +01005368/* Initialisation sequence for Maxdata Favorit 100XS
5369 * (adapted from Acer init verbs).
5370 */
5371static struct hda_verb alc260_favorit100_init_verbs[] = {
5372 /* GPIO 0 enables the output jack.
5373 * Turn this on and rely on the standard mute
5374 * methods whenever the user wants to turn these outputs off.
5375 */
5376 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
5377 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
5378 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
5379 /* Line/Mic input jack is connected to Mic1 pin */
5380 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
5381 /* Ensure all other unused pins are disabled and muted. */
5382 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5383 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5384 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5385 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5386 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5387 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5388 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5389 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5390 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5391 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5392 /* Disable digital (SPDIF) pins */
5393 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5394 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
5395
5396 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
5397 * bus when acting as outputs.
5398 */
5399 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
5400 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5401
5402 /* Start with output sum widgets muted and their output gains at min */
5403 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5404 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5405 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5406 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5407 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5408 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5409 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5410 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5411 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5412
5413 /* Unmute Line-out pin widget amp left and right
5414 * (no equiv mixer ctrl)
5415 */
5416 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5417 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
5418 * inputs. If the pin mode is changed by the user the pin mode control
5419 * will take care of enabling the pin's input/output buffers as needed.
5420 * Therefore there's no need to enable the input buffer at this
5421 * stage.
5422 */
5423 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5424
5425 /* Mute capture amp left and right */
5426 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5427 /* Set ADC connection select to match default mixer setting - mic
5428 * (on mic1 pin)
5429 */
5430 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5431
5432 /* Do similar with the second ADC: mute capture input amp and
5433 * set ADC connection to mic to match ALSA's default state.
5434 */
5435 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5436 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
5437
5438 /* Mute all inputs to mixer widget (even unconnected ones) */
5439 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5440 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5441 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5442 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5443 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5444 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5445 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5446 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
5447
5448 { }
5449};
5450
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005451static struct hda_verb alc260_will_verbs[] = {
5452 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5453 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
5454 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
5455 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
5456 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
5457 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
5458 {}
5459};
5460
5461static struct hda_verb alc260_replacer_672v_verbs[] = {
5462 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
5463 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
5464 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
5465
5466 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
5467 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
5468 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
5469
5470 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5471 {}
5472};
5473
5474/* toggle speaker-output according to the hp-jack state */
5475static void alc260_replacer_672v_automute(struct hda_codec *codec)
5476{
5477 unsigned int present;
5478
5479 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
5480 present = snd_hda_codec_read(codec, 0x0f, 0,
5481 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
5482 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005483 snd_hda_codec_write_cache(codec, 0x01, 0,
5484 AC_VERB_SET_GPIO_DATA, 1);
5485 snd_hda_codec_write_cache(codec, 0x0f, 0,
5486 AC_VERB_SET_PIN_WIDGET_CONTROL,
5487 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005488 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005489 snd_hda_codec_write_cache(codec, 0x01, 0,
5490 AC_VERB_SET_GPIO_DATA, 0);
5491 snd_hda_codec_write_cache(codec, 0x0f, 0,
5492 AC_VERB_SET_PIN_WIDGET_CONTROL,
5493 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005494 }
5495}
5496
5497static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
5498 unsigned int res)
5499{
5500 if ((res >> 26) == ALC880_HP_EVENT)
5501 alc260_replacer_672v_automute(codec);
5502}
5503
Kailang Yang3f878302008-08-26 13:02:23 +02005504static struct hda_verb alc260_hp_dc7600_verbs[] = {
5505 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
5506 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
5507 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5508 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5509 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5510 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5511 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5512 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5513 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5514 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5515 {}
5516};
5517
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005518/* Test configuration for debugging, modelled after the ALC880 test
5519 * configuration.
5520 */
5521#ifdef CONFIG_SND_DEBUG
5522static hda_nid_t alc260_test_dac_nids[1] = {
5523 0x02,
5524};
5525static hda_nid_t alc260_test_adc_nids[2] = {
5526 0x04, 0x05,
5527};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005528/* For testing the ALC260, each input MUX needs its own definition since
Kailang Yangea1fb292008-08-26 12:58:38 +02005529 * the signal assignments are different. This assumes that the first ADC
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005530 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01005531 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005532static struct hda_input_mux alc260_test_capture_sources[2] = {
5533 {
5534 .num_items = 7,
5535 .items = {
5536 { "MIC1 pin", 0x0 },
5537 { "MIC2 pin", 0x1 },
5538 { "LINE1 pin", 0x2 },
5539 { "LINE2 pin", 0x3 },
5540 { "CD pin", 0x4 },
5541 { "LINE-OUT pin", 0x5 },
5542 { "HP-OUT pin", 0x6 },
5543 },
5544 },
5545 {
5546 .num_items = 8,
5547 .items = {
5548 { "MIC1 pin", 0x0 },
5549 { "MIC2 pin", 0x1 },
5550 { "LINE1 pin", 0x2 },
5551 { "LINE2 pin", 0x3 },
5552 { "CD pin", 0x4 },
5553 { "Mixer", 0x5 },
5554 { "LINE-OUT pin", 0x6 },
5555 { "HP-OUT pin", 0x7 },
5556 },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005557 },
5558};
5559static struct snd_kcontrol_new alc260_test_mixer[] = {
5560 /* Output driver widgets */
5561 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5562 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5563 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5564 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
5565 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5566 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
5567
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005568 /* Modes for retasking pin widgets
5569 * Note: the ALC260 doesn't seem to act on requests to enable mic
5570 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
5571 * mention this restriction. At this stage it's not clear whether
5572 * this behaviour is intentional or is a hardware bug in chip
5573 * revisions available at least up until early 2006. Therefore for
5574 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
5575 * choices, but if it turns out that the lack of mic bias for these
5576 * NIDs is intentional we could change their modes from
5577 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
5578 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005579 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
5580 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
5581 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
5582 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
5583 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
5584 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
5585
5586 /* Loopback mixer controls */
5587 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
5588 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
5589 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
5590 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
5591 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
5592 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
5593 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
5594 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
5595 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5596 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005597 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
5598 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
5599 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
5600 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01005601
5602 /* Controls for GPIO pins, assuming they are configured as outputs */
5603 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
5604 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
5605 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
5606 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
5607
Jonathan Woithe92621f12006-02-28 11:47:47 +01005608 /* Switches to allow the digital IO pins to be enabled. The datasheet
5609 * is ambigious as to which NID is which; testing on laptops which
Kailang Yangea1fb292008-08-26 12:58:38 +02005610 * make this output available should provide clarification.
Jonathan Woithe92621f12006-02-28 11:47:47 +01005611 */
5612 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
5613 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
5614
Jonathan Woithef8225f62008-01-08 12:16:54 +01005615 /* A switch allowing EAPD to be enabled. Some laptops seem to use
5616 * this output to turn on an external amplifier.
5617 */
5618 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
5619 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
5620
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005621 { } /* end */
5622};
5623static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01005624 /* Enable all GPIOs as outputs with an initial value of 0 */
5625 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
5626 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
5627 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
5628
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005629 /* Enable retasking pins as output, initially without power amp */
5630 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5631 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5632 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5633 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5634 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5635 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5636
Jonathan Woithe92621f12006-02-28 11:47:47 +01005637 /* Disable digital (SPDIF) pins initially, but users can enable
5638 * them via a mixer switch. In the case of SPDIF-out, this initverb
5639 * payload also sets the generation to 0, output to be in "consumer"
5640 * PCM format, copyright asserted, no pre-emphasis and no validity
5641 * control.
5642 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005643 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5644 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
5645
Kailang Yangea1fb292008-08-26 12:58:38 +02005646 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005647 * OUT1 sum bus when acting as an output.
5648 */
5649 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
5650 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
5651 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5652 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
5653
5654 /* Start with output sum widgets muted and their output gains at min */
5655 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5656 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5657 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5658 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5659 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5660 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5661 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5662 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5663 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5664
Jonathan Woithecdcd9262006-02-28 11:36:42 +01005665 /* Unmute retasking pin widget output buffers since the default
5666 * state appears to be output. As the pin mode is changed by the
5667 * user the pin mode control will take care of enabling the pin's
5668 * input/output buffers as needed.
5669 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005670 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5671 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5672 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5673 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5674 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5675 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5676 /* Also unmute the mono-out pin widget */
5677 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5678
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005679 /* Mute capture amp left and right */
5680 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005681 /* Set ADC connection select to match default mixer setting (mic1
5682 * pin)
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005683 */
5684 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5685
5686 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01005687 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005688 */
5689 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5690 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
5691
5692 /* Mute all inputs to mixer widget (even unconnected ones) */
5693 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5694 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5695 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5696 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5697 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5698 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5699 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5700 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
5701
5702 { }
5703};
5704#endif
5705
Takashi Iwai63300792008-01-24 15:31:36 +01005706#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
5707#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07005708
Takashi Iwaia3bcba32005-12-06 19:05:29 +01005709#define alc260_pcm_digital_playback alc880_pcm_digital_playback
5710#define alc260_pcm_digital_capture alc880_pcm_digital_capture
5711
Kailang Yangdf694da2005-12-05 19:42:22 +01005712/*
5713 * for BIOS auto-configuration
5714 */
5715
5716static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai863b4512008-10-21 17:01:47 +02005717 const char *pfx, int *vol_bits)
Kailang Yangdf694da2005-12-05 19:42:22 +01005718{
5719 hda_nid_t nid_vol;
5720 unsigned long vol_val, sw_val;
5721 char name[32];
5722 int err;
5723
5724 if (nid >= 0x0f && nid < 0x11) {
5725 nid_vol = nid - 0x7;
5726 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
5727 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
5728 } else if (nid == 0x11) {
5729 nid_vol = nid - 0x7;
5730 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
5731 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
5732 } else if (nid >= 0x12 && nid <= 0x15) {
5733 nid_vol = 0x08;
5734 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
5735 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
5736 } else
5737 return 0; /* N/A */
Kailang Yangea1fb292008-08-26 12:58:38 +02005738
Takashi Iwai863b4512008-10-21 17:01:47 +02005739 if (!(*vol_bits & (1 << nid_vol))) {
5740 /* first control for the volume widget */
5741 snprintf(name, sizeof(name), "%s Playback Volume", pfx);
5742 err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val);
5743 if (err < 0)
5744 return err;
5745 *vol_bits |= (1 << nid_vol);
5746 }
Kailang Yangdf694da2005-12-05 19:42:22 +01005747 snprintf(name, sizeof(name), "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005748 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val);
5749 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005750 return err;
5751 return 1;
5752}
5753
5754/* add playback controls from the parsed DAC table */
5755static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
5756 const struct auto_pin_cfg *cfg)
5757{
5758 hda_nid_t nid;
5759 int err;
Takashi Iwai863b4512008-10-21 17:01:47 +02005760 int vols = 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01005761
5762 spec->multiout.num_dacs = 1;
5763 spec->multiout.dac_nids = spec->private_dac_nids;
5764 spec->multiout.dac_nids[0] = 0x02;
5765
5766 nid = cfg->line_out_pins[0];
5767 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02005768 err = alc260_add_playback_controls(spec, nid, "Front", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01005769 if (err < 0)
5770 return err;
5771 }
5772
Takashi Iwai82bc9552006-03-21 11:24:42 +01005773 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005774 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02005775 err = alc260_add_playback_controls(spec, nid, "Speaker", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01005776 if (err < 0)
5777 return err;
5778 }
5779
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005780 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005781 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02005782 err = alc260_add_playback_controls(spec, nid, "Headphone",
5783 &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01005784 if (err < 0)
5785 return err;
5786 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005787 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01005788}
5789
5790/* create playback/capture controls for input pins */
5791static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec,
5792 const struct auto_pin_cfg *cfg)
5793{
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005794 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005795 int i, err, idx;
5796
5797 for (i = 0; i < AUTO_PIN_LAST; i++) {
5798 if (cfg->input_pins[i] >= 0x12) {
5799 idx = cfg->input_pins[i] - 0x12;
Takashi Iwai4a471b72005-12-07 13:56:29 +01005800 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005801 auto_pin_cfg_labels[i], idx,
5802 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01005803 if (err < 0)
5804 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005805 imux->items[imux->num_items].label =
5806 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01005807 imux->items[imux->num_items].index = idx;
5808 imux->num_items++;
5809 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005810 if (cfg->input_pins[i] >= 0x0f && cfg->input_pins[i] <= 0x10){
Kailang Yangdf694da2005-12-05 19:42:22 +01005811 idx = cfg->input_pins[i] - 0x09;
Takashi Iwai4a471b72005-12-07 13:56:29 +01005812 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005813 auto_pin_cfg_labels[i], idx,
5814 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01005815 if (err < 0)
5816 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005817 imux->items[imux->num_items].label =
5818 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01005819 imux->items[imux->num_items].index = idx;
5820 imux->num_items++;
5821 }
5822 }
5823 return 0;
5824}
5825
5826static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
5827 hda_nid_t nid, int pin_type,
5828 int sel_idx)
5829{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005830 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01005831 /* need the manual connection? */
5832 if (nid >= 0x12) {
5833 int idx = nid - 0x12;
5834 snd_hda_codec_write(codec, idx + 0x0b, 0,
5835 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01005836 }
5837}
5838
5839static void alc260_auto_init_multi_out(struct hda_codec *codec)
5840{
5841 struct alc_spec *spec = codec->spec;
5842 hda_nid_t nid;
5843
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005844 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005845 if (nid) {
5846 int pin_type = get_pin_type(spec->autocfg.line_out_type);
5847 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
5848 }
Kailang Yangea1fb292008-08-26 12:58:38 +02005849
Takashi Iwai82bc9552006-03-21 11:24:42 +01005850 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005851 if (nid)
5852 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
5853
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005854 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005855 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005856 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005857}
Kailang Yangdf694da2005-12-05 19:42:22 +01005858
5859#define ALC260_PIN_CD_NID 0x16
5860static void alc260_auto_init_analog_input(struct hda_codec *codec)
5861{
5862 struct alc_spec *spec = codec->spec;
5863 int i;
5864
5865 for (i = 0; i < AUTO_PIN_LAST; i++) {
5866 hda_nid_t nid = spec->autocfg.input_pins[i];
5867 if (nid >= 0x12) {
Takashi Iwai23f0c042009-02-26 13:03:58 +01005868 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +01005869 if (nid != ALC260_PIN_CD_NID &&
5870 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005871 snd_hda_codec_write(codec, nid, 0,
5872 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01005873 AMP_OUT_MUTE);
5874 }
5875 }
5876}
5877
5878/*
5879 * generic initialization of ADC, input mixers and output mixers
5880 */
5881static struct hda_verb alc260_volume_init_verbs[] = {
5882 /*
5883 * Unmute ADC0-1 and set the default input to mic-in
5884 */
5885 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5886 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5887 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
5888 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02005889
Kailang Yangdf694da2005-12-05 19:42:22 +01005890 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
5891 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005892 * Note: PASD motherboards uses the Line In 2 as the input for
5893 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01005894 */
5895 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005896 /* mute analog inputs */
5897 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5898 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5899 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5900 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5901 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005902
5903 /*
5904 * Set up output mixers (0x08 - 0x0a)
5905 */
5906 /* set vol=0 to output mixers */
5907 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5908 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5909 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5910 /* set up input amps for analog loopback */
5911 /* Amp Indices: DAC = 0, mixer = 1 */
5912 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5913 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5914 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5915 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5916 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5917 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +02005918
Kailang Yangdf694da2005-12-05 19:42:22 +01005919 { }
5920};
5921
5922static int alc260_parse_auto_config(struct hda_codec *codec)
5923{
5924 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005925 int err;
5926 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
5927
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005928 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
5929 alc260_ignore);
5930 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005931 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005932 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
5933 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01005934 return err;
Takashi Iwai603c4012008-07-30 15:01:44 +02005935 if (!spec->kctls.list)
Kailang Yangdf694da2005-12-05 19:42:22 +01005936 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005937 err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg);
5938 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005939 return err;
5940
5941 spec->multiout.max_channels = 2;
5942
Takashi Iwai0852d7a2009-02-11 11:35:15 +01005943 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +01005944 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
Takashi Iwai603c4012008-07-30 15:01:44 +02005945 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01005946 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +01005947
Takashi Iwaid88897e2008-10-31 15:01:37 +01005948 add_verb(spec, alc260_volume_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +01005949
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005950 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005951 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005952
Takashi Iwai4a79ba342009-04-22 16:31:35 +02005953 alc_ssid_check(codec, 0x10, 0x15, 0x0f);
5954
Kailang Yangdf694da2005-12-05 19:42:22 +01005955 return 1;
5956}
5957
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005958/* additional initialization for auto-configuration model */
5959static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01005960{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005961 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005962 alc260_auto_init_multi_out(codec);
5963 alc260_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005964 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02005965 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01005966}
5967
Takashi Iwaicb53c622007-08-10 17:21:45 +02005968#ifdef CONFIG_SND_HDA_POWER_SAVE
5969static struct hda_amp_list alc260_loopbacks[] = {
5970 { 0x07, HDA_INPUT, 0 },
5971 { 0x07, HDA_INPUT, 1 },
5972 { 0x07, HDA_INPUT, 2 },
5973 { 0x07, HDA_INPUT, 3 },
5974 { 0x07, HDA_INPUT, 4 },
5975 { } /* end */
5976};
5977#endif
5978
Kailang Yangdf694da2005-12-05 19:42:22 +01005979/*
5980 * ALC260 configurations
5981 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005982static const char *alc260_models[ALC260_MODEL_LAST] = {
5983 [ALC260_BASIC] = "basic",
5984 [ALC260_HP] = "hp",
5985 [ALC260_HP_3013] = "hp-3013",
Takashi Iwai2922c9a2008-08-27 18:12:42 +02005986 [ALC260_HP_DC7600] = "hp-dc7600",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005987 [ALC260_FUJITSU_S702X] = "fujitsu",
5988 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005989 [ALC260_WILL] = "will",
5990 [ALC260_REPLACER_672V] = "replacer",
Michael Schwingencc959482009-02-22 18:58:45 +01005991 [ALC260_FAVORIT100] = "favorit100",
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005992#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005993 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005994#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005995 [ALC260_AUTO] = "auto",
5996};
5997
5998static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01005999 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006000 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Michael Schwingencc959482009-02-22 18:58:45 +01006001 SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100),
Takashi Iwai9720b712007-03-13 21:46:23 +01006002 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwaia8a5d062007-03-15 15:10:28 +01006003 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006004 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
Jaroslav Kysela34ec8a02008-07-10 14:49:19 +02006005 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
Kailang Yang3f878302008-08-26 13:02:23 +02006006 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006007 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
6008 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
6009 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
6010 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
6011 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
6012 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
6013 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
6014 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
6015 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006016 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006017 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02006018 {}
6019};
6020
Kailang Yangdf694da2005-12-05 19:42:22 +01006021static struct alc_config_preset alc260_presets[] = {
6022 [ALC260_BASIC] = {
6023 .mixers = { alc260_base_output_mixer,
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01006024 alc260_input_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01006025 .init_verbs = { alc260_init_verbs },
6026 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6027 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006028 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
Kailang Yangdf694da2005-12-05 19:42:22 +01006029 .adc_nids = alc260_adc_nids,
6030 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6031 .channel_mode = alc260_modes,
6032 .input_mux = &alc260_capture_source,
6033 },
6034 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006035 .mixers = { alc260_hp_output_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006036 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01006037 .init_verbs = { alc260_init_verbs,
6038 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01006039 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6040 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006041 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
6042 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01006043 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6044 .channel_mode = alc260_modes,
6045 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006046 .unsol_event = alc260_hp_unsol_event,
6047 .init_hook = alc260_hp_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01006048 },
Kailang Yang3f878302008-08-26 13:02:23 +02006049 [ALC260_HP_DC7600] = {
6050 .mixers = { alc260_hp_dc7600_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006051 alc260_input_mixer },
Kailang Yang3f878302008-08-26 13:02:23 +02006052 .init_verbs = { alc260_init_verbs,
6053 alc260_hp_dc7600_verbs },
6054 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6055 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006056 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
6057 .adc_nids = alc260_adc_nids_alt,
Kailang Yang3f878302008-08-26 13:02:23 +02006058 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6059 .channel_mode = alc260_modes,
6060 .input_mux = &alc260_capture_source,
6061 .unsol_event = alc260_hp_3012_unsol_event,
6062 .init_hook = alc260_hp_3012_automute,
6063 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006064 [ALC260_HP_3013] = {
6065 .mixers = { alc260_hp_3013_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006066 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01006067 .init_verbs = { alc260_hp_3013_init_verbs,
6068 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01006069 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6070 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006071 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
6072 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01006073 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6074 .channel_mode = alc260_modes,
6075 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006076 .unsol_event = alc260_hp_3013_unsol_event,
6077 .init_hook = alc260_hp_3013_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01006078 },
6079 [ALC260_FUJITSU_S702X] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006080 .mixers = { alc260_fujitsu_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01006081 .init_verbs = { alc260_fujitsu_init_verbs },
6082 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6083 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01006084 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
6085 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01006086 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6087 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006088 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
6089 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01006090 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006091 [ALC260_ACER] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006092 .mixers = { alc260_acer_mixer },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006093 .init_verbs = { alc260_acer_init_verbs },
6094 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6095 .dac_nids = alc260_dac_nids,
6096 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
6097 .adc_nids = alc260_dual_adc_nids,
6098 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6099 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006100 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
6101 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006102 },
Michael Schwingencc959482009-02-22 18:58:45 +01006103 [ALC260_FAVORIT100] = {
6104 .mixers = { alc260_favorit100_mixer },
6105 .init_verbs = { alc260_favorit100_init_verbs },
6106 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6107 .dac_nids = alc260_dac_nids,
6108 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
6109 .adc_nids = alc260_dual_adc_nids,
6110 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6111 .channel_mode = alc260_modes,
6112 .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources),
6113 .input_mux = alc260_favorit100_capture_sources,
6114 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006115 [ALC260_WILL] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006116 .mixers = { alc260_will_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006117 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
6118 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6119 .dac_nids = alc260_dac_nids,
6120 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
6121 .adc_nids = alc260_adc_nids,
6122 .dig_out_nid = ALC260_DIGOUT_NID,
6123 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6124 .channel_mode = alc260_modes,
6125 .input_mux = &alc260_capture_source,
6126 },
6127 [ALC260_REPLACER_672V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006128 .mixers = { alc260_replacer_672v_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006129 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
6130 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6131 .dac_nids = alc260_dac_nids,
6132 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
6133 .adc_nids = alc260_adc_nids,
6134 .dig_out_nid = ALC260_DIGOUT_NID,
6135 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6136 .channel_mode = alc260_modes,
6137 .input_mux = &alc260_capture_source,
6138 .unsol_event = alc260_replacer_672v_unsol_event,
6139 .init_hook = alc260_replacer_672v_automute,
6140 },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006141#ifdef CONFIG_SND_DEBUG
6142 [ALC260_TEST] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006143 .mixers = { alc260_test_mixer },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006144 .init_verbs = { alc260_test_init_verbs },
6145 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
6146 .dac_nids = alc260_test_dac_nids,
6147 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
6148 .adc_nids = alc260_test_adc_nids,
6149 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6150 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006151 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
6152 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006153 },
6154#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01006155};
6156
Linus Torvalds1da177e2005-04-16 15:20:36 -07006157static int patch_alc260(struct hda_codec *codec)
6158{
6159 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006160 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006161
Takashi Iwaie560d8d2005-09-09 14:21:46 +02006162 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006163 if (spec == NULL)
6164 return -ENOMEM;
6165
6166 codec->spec = spec;
6167
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006168 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
6169 alc260_models,
6170 alc260_cfg_tbl);
6171 if (board_config < 0) {
Takashi Iwai6c627f32009-05-18 12:33:36 +02006172 snd_printd(KERN_INFO "hda_codec: Unknown model for %s, "
6173 "trying auto-probe from BIOS...\n",
6174 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +01006175 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02006176 }
6177
Kailang Yangdf694da2005-12-05 19:42:22 +01006178 if (board_config == ALC260_AUTO) {
6179 /* automatic parse from the BIOS config */
6180 err = alc260_parse_auto_config(codec);
6181 if (err < 0) {
6182 alc_free(codec);
6183 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006184 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006185 printk(KERN_INFO
6186 "hda_codec: Cannot set up configuration "
6187 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01006188 board_config = ALC260_BASIC;
6189 }
Takashi Iwai16ded522005-06-10 19:58:24 +02006190 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006191
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09006192 err = snd_hda_attach_beep_device(codec, 0x1);
6193 if (err < 0) {
6194 alc_free(codec);
6195 return err;
6196 }
6197
Kailang Yangdf694da2005-12-05 19:42:22 +01006198 if (board_config != ALC260_AUTO)
6199 setup_preset(spec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006200
Linus Torvalds1da177e2005-04-16 15:20:36 -07006201 spec->stream_analog_playback = &alc260_pcm_analog_playback;
6202 spec->stream_analog_capture = &alc260_pcm_analog_capture;
6203
Takashi Iwaia3bcba32005-12-06 19:05:29 +01006204 spec->stream_digital_playback = &alc260_pcm_digital_playback;
6205 spec->stream_digital_capture = &alc260_pcm_digital_capture;
6206
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01006207 if (!spec->adc_nids && spec->input_mux) {
6208 /* check whether NID 0x04 is valid */
6209 unsigned int wcap = get_wcaps(codec, 0x04);
6210 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
6211 /* get type */
6212 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
6213 spec->adc_nids = alc260_adc_nids_alt;
6214 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
6215 } else {
6216 spec->adc_nids = alc260_adc_nids;
6217 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
6218 }
6219 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006220 set_capture_mixer(spec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01006221 set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006222
Takashi Iwai2134ea42008-01-10 16:53:55 +01006223 spec->vmaster_nid = 0x08;
6224
Linus Torvalds1da177e2005-04-16 15:20:36 -07006225 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01006226 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006227 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02006228#ifdef CONFIG_SND_HDA_POWER_SAVE
6229 if (!spec->loopback.amplist)
6230 spec->loopback.amplist = alc260_loopbacks;
6231#endif
Takashi Iwaidaead532008-11-28 12:55:36 +01006232 codec->proc_widget_hook = print_realtek_coef;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006233
6234 return 0;
6235}
6236
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006237
Linus Torvalds1da177e2005-04-16 15:20:36 -07006238/*
6239 * ALC882 support
6240 *
6241 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
6242 * configuration. Each pin widget can choose any input DACs and a mixer.
6243 * Each ADC is connected from a mixer of all inputs. This makes possible
6244 * 6-channel independent captures.
6245 *
6246 * In addition, an independent DAC for the multi-playback (not used in this
6247 * driver yet).
6248 */
Kailang Yangdf694da2005-12-05 19:42:22 +01006249#define ALC882_DIGOUT_NID 0x06
6250#define ALC882_DIGIN_NID 0x0a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006251
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01006252static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006253 { 8, NULL }
6254};
6255
6256static hda_nid_t alc882_dac_nids[4] = {
6257 /* front, rear, clfe, rear_surr */
6258 0x02, 0x03, 0x04, 0x05
6259};
6260
Kailang Yangdf694da2005-12-05 19:42:22 +01006261/* identical with ALC880 */
6262#define alc882_adc_nids alc880_adc_nids
6263#define alc882_adc_nids_alt alc880_adc_nids_alt
Linus Torvalds1da177e2005-04-16 15:20:36 -07006264
Takashi Iwaie1406342008-02-11 18:32:32 +01006265static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
6266static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
6267
Linus Torvalds1da177e2005-04-16 15:20:36 -07006268/* input MUX */
6269/* FIXME: should be a matrix-type input source selection */
6270
6271static struct hda_input_mux alc882_capture_source = {
6272 .num_items = 4,
6273 .items = {
6274 { "Mic", 0x0 },
6275 { "Front Mic", 0x1 },
6276 { "Line", 0x2 },
6277 { "CD", 0x4 },
6278 },
6279};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02006280
6281static struct hda_input_mux mb5_capture_source = {
6282 .num_items = 3,
6283 .items = {
6284 { "Mic", 0x1 },
6285 { "Line", 0x2 },
6286 { "CD", 0x4 },
6287 },
6288};
6289
Kailang Yangdf694da2005-12-05 19:42:22 +01006290/*
Kailang Yang272a5272007-05-14 11:00:38 +02006291 * 2ch mode
6292 */
6293static struct hda_verb alc882_3ST_ch2_init[] = {
6294 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6295 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6296 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6297 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6298 { } /* end */
6299};
6300
6301/*
6302 * 6ch mode
6303 */
6304static struct hda_verb alc882_3ST_ch6_init[] = {
6305 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6306 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6307 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
6308 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6309 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6310 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6311 { } /* end */
6312};
6313
6314static struct hda_channel_mode alc882_3ST_6ch_modes[2] = {
6315 { 2, alc882_3ST_ch2_init },
6316 { 6, alc882_3ST_ch6_init },
6317};
6318
6319/*
Kailang Yangdf694da2005-12-05 19:42:22 +01006320 * 6ch mode
6321 */
6322static struct hda_verb alc882_sixstack_ch6_init[] = {
6323 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
6324 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6325 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6326 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6327 { } /* end */
6328};
6329
6330/*
6331 * 8ch mode
6332 */
6333static struct hda_verb alc882_sixstack_ch8_init[] = {
6334 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6335 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6336 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6337 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6338 { } /* end */
6339};
6340
6341static struct hda_channel_mode alc882_sixstack_modes[2] = {
6342 { 6, alc882_sixstack_ch6_init },
6343 { 8, alc882_sixstack_ch8_init },
6344};
6345
Takashi Iwai87350ad2007-08-16 18:19:38 +02006346/*
6347 * macbook pro ALC885 can switch LineIn to LineOut without loosing Mic
6348 */
6349
6350/*
6351 * 2ch mode
6352 */
6353static struct hda_verb alc885_mbp_ch2_init[] = {
6354 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6355 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6356 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6357 { } /* end */
6358};
6359
6360/*
6361 * 6ch mode
6362 */
6363static struct hda_verb alc885_mbp_ch6_init[] = {
6364 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6365 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6366 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6367 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6368 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6369 { } /* end */
6370};
6371
6372static struct hda_channel_mode alc885_mbp_6ch_modes[2] = {
6373 { 2, alc885_mbp_ch2_init },
6374 { 6, alc885_mbp_ch6_init },
6375};
6376
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02006377/*
6378 * 2ch
6379 * Speakers/Woofer/HP = Front
6380 * LineIn = Input
6381 */
6382static struct hda_verb alc885_mb5_ch2_init[] = {
6383 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6384 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6385 { } /* end */
6386};
6387
6388/*
6389 * 6ch mode
6390 * Speakers/HP = Front
6391 * Woofer = LFE
6392 * LineIn = Surround
6393 */
6394static struct hda_verb alc885_mb5_ch6_init[] = {
6395 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6396 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6397 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
6398 { } /* end */
6399};
6400
6401static struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
6402 { 2, alc885_mb5_ch2_init },
6403 { 6, alc885_mb5_ch6_init },
6404};
Takashi Iwai87350ad2007-08-16 18:19:38 +02006405
Linus Torvalds1da177e2005-04-16 15:20:36 -07006406/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
6407 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
6408 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01006409static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02006410 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006411 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02006412 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006413 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02006414 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6415 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006416 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6417 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02006418 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006419 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006420 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6421 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6422 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6423 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6424 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6425 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006426 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006427 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6428 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006429 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006430 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006431 { } /* end */
6432};
6433
Takashi Iwai87350ad2007-08-16 18:19:38 +02006434static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01006435 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
6436 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
6437 HDA_CODEC_MUTE ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT),
6438 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
6439 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6440 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02006441 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
6442 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01006443 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02006444 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
6445 { } /* end */
6446};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02006447
6448static struct snd_kcontrol_new alc885_mb5_mixer[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02006449 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
6450 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
6451 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
6452 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
6453 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
6454 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
6455 HDA_CODEC_VOLUME("HP Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
6456 HDA_BIND_MUTE ("HP Playback Switch", 0x0f, 0x02, HDA_INPUT),
Kacper Szczesniak41d55452009-05-07 12:47:43 +02006457 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6458 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6459 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
6460 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
6461 HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT),
6462 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0x00, HDA_INPUT),
6463 { } /* end */
6464};
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02006465
Kailang Yangbdd148a2007-05-08 15:19:08 +02006466static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
6467 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6468 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6469 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6470 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6471 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6472 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6473 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6474 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6475 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02006476 { } /* end */
6477};
6478
Kailang Yang272a5272007-05-14 11:00:38 +02006479static struct snd_kcontrol_new alc882_targa_mixer[] = {
6480 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6481 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6482 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6483 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6484 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6485 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6486 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6487 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6488 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02006489 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02006490 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6491 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02006492 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02006493 { } /* end */
6494};
6495
6496/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
6497 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
6498 */
6499static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
6500 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6501 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6502 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6503 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
6504 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6505 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6506 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6507 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6508 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
6509 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
6510 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6511 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02006512 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02006513 { } /* end */
6514};
6515
Takashi Iwai914759b2007-09-06 14:52:04 +02006516static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
6517 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6518 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6519 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6520 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6521 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6522 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6523 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6524 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6525 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6526 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02006527 { } /* end */
6528};
6529
Kailang Yangdf694da2005-12-05 19:42:22 +01006530static struct snd_kcontrol_new alc882_chmode_mixer[] = {
6531 {
6532 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6533 .name = "Channel Mode",
6534 .info = alc_ch_mode_info,
6535 .get = alc_ch_mode_get,
6536 .put = alc_ch_mode_put,
6537 },
6538 { } /* end */
6539};
6540
Linus Torvalds1da177e2005-04-16 15:20:36 -07006541static struct hda_verb alc882_init_verbs[] = {
6542 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02006543 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6544 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6545 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006546 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02006547 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6548 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6549 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006550 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02006551 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6552 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6553 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006554 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02006555 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6556 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6557 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006558
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006559 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02006560 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02006561 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006562 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006563 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02006564 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02006565 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006566 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006567 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02006568 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02006569 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006570 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006571 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02006572 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02006573 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006574 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006575 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006576 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006577 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6578 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006579 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006580 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6581 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006582 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006583 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6584 /* Line-2 In: Headphone output (output 0 - 0x0c) */
6585 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6586 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6587 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006588 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006589 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006590
6591 /* FIXME: use matrix-type input source selection */
6592 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6593 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Takashi Iwai05acb862005-06-10 19:50:25 +02006594 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6595 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6596 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6597 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006598 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02006599 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6600 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6601 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6602 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006603 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02006604 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6605 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6606 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6607 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6608 /* ADC1: mute amp left and right */
6609 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02006610 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02006611 /* ADC2: mute amp left and right */
6612 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02006613 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02006614 /* ADC3: mute amp left and right */
6615 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02006616 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006617
6618 { }
6619};
6620
Takashi Iwai4b146cb2006-07-28 14:42:36 +02006621static struct hda_verb alc882_eapd_verbs[] = {
6622 /* change to EAPD mode */
6623 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01006624 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006625 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02006626};
6627
Tobin Davis9102cd12006-12-15 10:02:12 +01006628/* Mac Pro test */
6629static struct snd_kcontrol_new alc882_macpro_mixer[] = {
6630 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6631 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6632 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
6633 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
6634 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01006635 /* FIXME: this looks suspicious...
Tobin Davis9102cd12006-12-15 10:02:12 +01006636 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT),
6637 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01006638 */
Tobin Davis9102cd12006-12-15 10:02:12 +01006639 { } /* end */
6640};
6641
6642static struct hda_verb alc882_macpro_init_verbs[] = {
6643 /* Front mixer: unmute input/output amp left and right (volume = 0) */
6644 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6645 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6646 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6647 /* Front Pin: output 0 (0x0c) */
6648 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6649 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6650 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
6651 /* Front Mic pin: input vref at 80% */
6652 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6653 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6654 /* Speaker: output */
6655 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6656 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6657 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
6658 /* Headphone output (output 0 - 0x0c) */
6659 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6660 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6661 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
6662
6663 /* FIXME: use matrix-type input source selection */
6664 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6665 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6666 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6667 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6668 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6669 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6670 /* Input mixer2 */
6671 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6672 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6673 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6674 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6675 /* Input mixer3 */
6676 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6677 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6678 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6679 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6680 /* ADC1: mute amp left and right */
6681 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6682 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6683 /* ADC2: mute amp left and right */
6684 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6685 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6686 /* ADC3: mute amp left and right */
6687 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6688 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6689
6690 { }
6691};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006692
Kacper Szczesniak41d55452009-05-07 12:47:43 +02006693/* Macbook 5,1 */
6694static struct hda_verb alc885_mb5_init_verbs[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02006695 /* DACs */
6696 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6697 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6698 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6699 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02006700 /* Front mixer */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02006701 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6702 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6703 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02006704 /* Surround mixer */
6705 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6706 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6707 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6708 /* LFE mixer */
6709 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6710 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6711 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6712 /* HP mixer */
6713 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6714 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6715 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6716 /* Front Pin (0x0c) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02006717 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
6718 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02006719 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
6720 /* LFE Pin (0x0e) */
6721 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
6722 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6723 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
6724 /* HP Pin (0x0f) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02006725 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6726 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02006727 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02006728 /* Front Mic pin: input vref at 80% */
6729 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6730 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6731 /* Line In pin */
6732 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6733 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6734
6735 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6736 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6737 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6738 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6739 { }
6740};
6741
Takashi Iwai87350ad2007-08-16 18:19:38 +02006742/* Macbook Pro rev3 */
6743static struct hda_verb alc885_mbp3_init_verbs[] = {
6744 /* Front mixer: unmute input/output amp left and right (volume = 0) */
6745 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6746 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6747 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6748 /* Rear mixer */
6749 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6750 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6751 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6752 /* Front Pin: output 0 (0x0c) */
6753 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6754 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6755 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
6756 /* HP Pin: output 0 (0x0d) */
6757 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
6758 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6759 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
6760 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6761 /* Mic (rear) pin: input vref at 80% */
6762 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6763 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6764 /* Front Mic pin: input vref at 80% */
6765 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6766 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6767 /* Line In pin: use output 1 when in LineOut mode */
6768 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6769 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6770 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
6771
6772 /* FIXME: use matrix-type input source selection */
6773 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6774 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6775 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6776 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6777 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6778 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6779 /* Input mixer2 */
6780 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6781 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6782 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6783 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6784 /* Input mixer3 */
6785 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6786 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6787 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6788 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6789 /* ADC1: mute amp left and right */
6790 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6791 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6792 /* ADC2: mute amp left and right */
6793 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6794 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6795 /* ADC3: mute amp left and right */
6796 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6797 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6798
6799 { }
6800};
6801
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006802/* iMac 24 mixer. */
6803static struct snd_kcontrol_new alc885_imac24_mixer[] = {
6804 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
6805 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
6806 { } /* end */
6807};
6808
6809/* iMac 24 init verbs. */
6810static struct hda_verb alc885_imac24_init_verbs[] = {
6811 /* Internal speakers: output 0 (0x0c) */
6812 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6813 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6814 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
6815 /* Internal speakers: output 0 (0x0c) */
6816 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6817 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6818 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
6819 /* Headphone: output 0 (0x0c) */
6820 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6821 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6822 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
6823 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6824 /* Front Mic: input vref at 80% */
6825 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6826 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6827 { }
6828};
6829
6830/* Toggle speaker-output according to the hp-jack state */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02006831static void alc885_imac24_automute_init_hook(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006832{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02006833 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006834
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02006835 spec->autocfg.hp_pins[0] = 0x14;
6836 spec->autocfg.speaker_pins[0] = 0x18;
6837 spec->autocfg.speaker_pins[1] = 0x1a;
6838 alc_automute_amp(codec);
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006839}
6840
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02006841static void alc885_mbp3_init_hook(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006842{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02006843 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006844
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02006845 spec->autocfg.hp_pins[0] = 0x15;
6846 spec->autocfg.speaker_pins[0] = 0x14;
6847 alc_automute_amp(codec);
Takashi Iwai87350ad2007-08-16 18:19:38 +02006848}
6849
6850
Kailang Yang272a5272007-05-14 11:00:38 +02006851static struct hda_verb alc882_targa_verbs[] = {
6852 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6853 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6854
6855 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6856 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006857
Kailang Yang272a5272007-05-14 11:00:38 +02006858 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6859 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6860 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6861
6862 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6863 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
6864 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
6865 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
6866 { } /* end */
6867};
6868
6869/* toggle speaker-output according to the hp-jack state */
6870static void alc882_targa_automute(struct hda_codec *codec)
6871{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02006872 struct alc_spec *spec = codec->spec;
6873 alc_automute_amp(codec);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006874 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02006875 spec->jack_present ? 1 : 3);
6876}
6877
6878static void alc882_targa_init_hook(struct hda_codec *codec)
6879{
6880 struct alc_spec *spec = codec->spec;
6881
6882 spec->autocfg.hp_pins[0] = 0x14;
6883 spec->autocfg.speaker_pins[0] = 0x1b;
6884 alc882_targa_automute(codec);
Kailang Yang272a5272007-05-14 11:00:38 +02006885}
6886
6887static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
6888{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02006889 if ((res >> 26) == ALC880_HP_EVENT)
Kailang Yang272a5272007-05-14 11:00:38 +02006890 alc882_targa_automute(codec);
Kailang Yang272a5272007-05-14 11:00:38 +02006891}
6892
6893static struct hda_verb alc882_asus_a7j_verbs[] = {
6894 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6895 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6896
6897 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6898 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6899 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006900
Kailang Yang272a5272007-05-14 11:00:38 +02006901 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6902 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6903 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6904
6905 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6906 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6907 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6908 { } /* end */
6909};
6910
Takashi Iwai914759b2007-09-06 14:52:04 +02006911static struct hda_verb alc882_asus_a7m_verbs[] = {
6912 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6913 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6914
6915 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6916 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6917 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006918
Takashi Iwai914759b2007-09-06 14:52:04 +02006919 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6920 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6921 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6922
6923 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6924 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6925 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6926 { } /* end */
6927};
6928
Tobin Davis9102cd12006-12-15 10:02:12 +01006929static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
6930{
6931 unsigned int gpiostate, gpiomask, gpiodir;
6932
6933 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
6934 AC_VERB_GET_GPIO_DATA, 0);
6935
6936 if (!muted)
6937 gpiostate |= (1 << pin);
6938 else
6939 gpiostate &= ~(1 << pin);
6940
6941 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
6942 AC_VERB_GET_GPIO_MASK, 0);
6943 gpiomask |= (1 << pin);
6944
6945 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
6946 AC_VERB_GET_GPIO_DIRECTION, 0);
6947 gpiodir |= (1 << pin);
6948
6949
6950 snd_hda_codec_write(codec, codec->afg, 0,
6951 AC_VERB_SET_GPIO_MASK, gpiomask);
6952 snd_hda_codec_write(codec, codec->afg, 0,
6953 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
6954
6955 msleep(1);
6956
6957 snd_hda_codec_write(codec, codec->afg, 0,
6958 AC_VERB_SET_GPIO_DATA, gpiostate);
6959}
6960
Takashi Iwai7debbe52007-08-16 15:01:03 +02006961/* set up GPIO at initialization */
6962static void alc885_macpro_init_hook(struct hda_codec *codec)
6963{
6964 alc882_gpio_mute(codec, 0, 0);
6965 alc882_gpio_mute(codec, 1, 0);
6966}
6967
6968/* set up GPIO and update auto-muting at initialization */
6969static void alc885_imac24_init_hook(struct hda_codec *codec)
6970{
6971 alc885_macpro_init_hook(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02006972 alc885_imac24_automute_init_hook(codec);
Takashi Iwai7debbe52007-08-16 15:01:03 +02006973}
6974
Kailang Yangdf694da2005-12-05 19:42:22 +01006975/*
6976 * generic initialization of ADC, input mixers and output mixers
6977 */
6978static struct hda_verb alc882_auto_init_verbs[] = {
6979 /*
6980 * Unmute ADC0-2 and set the default input to mic-in
6981 */
6982 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6983 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6984 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6985 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6986 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6987 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6988
Takashi Iwaicb53c622007-08-10 17:21:45 +02006989 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01006990 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006991 * Note: PASD motherboards uses the Line In 2 as the input for
6992 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01006993 */
6994 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006995 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6996 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6997 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6998 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6999 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01007000
7001 /*
7002 * Set up output mixers (0x0c - 0x0f)
7003 */
7004 /* set vol=0 to output mixers */
7005 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7006 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7007 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7008 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7009 /* set up input amps for analog loopback */
7010 /* Amp Indices: DAC = 0, mixer = 1 */
7011 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7012 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7013 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7014 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7015 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7016 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7017 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7018 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7019 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7020 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7021
7022 /* FIXME: use matrix-type input source selection */
7023 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7024 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
7025 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
7026 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
7027 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
7028 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
7029 /* Input mixer2 */
7030 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
7031 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
7032 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
7033 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
7034 /* Input mixer3 */
7035 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
7036 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
7037 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
7038 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
7039
7040 { }
7041};
7042
Takashi Iwaicb53c622007-08-10 17:21:45 +02007043#ifdef CONFIG_SND_HDA_POWER_SAVE
7044#define alc882_loopbacks alc880_loopbacks
7045#endif
7046
Kailang Yangdf694da2005-12-05 19:42:22 +01007047/* pcm configuration: identiacal with ALC880 */
7048#define alc882_pcm_analog_playback alc880_pcm_analog_playback
7049#define alc882_pcm_analog_capture alc880_pcm_analog_capture
7050#define alc882_pcm_digital_playback alc880_pcm_digital_playback
7051#define alc882_pcm_digital_capture alc880_pcm_digital_capture
7052
7053/*
7054 * configuration and preset
7055 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007056static const char *alc882_models[ALC882_MODEL_LAST] = {
7057 [ALC882_3ST_DIG] = "3stack-dig",
7058 [ALC882_6ST_DIG] = "6stack-dig",
7059 [ALC882_ARIMA] = "arima",
Kailang Yangbdd148a2007-05-08 15:19:08 +02007060 [ALC882_W2JC] = "w2jc",
Takashi Iwai0438a002007-09-06 14:54:11 +02007061 [ALC882_TARGA] = "targa",
7062 [ALC882_ASUS_A7J] = "asus-a7j",
7063 [ALC882_ASUS_A7M] = "asus-a7m",
Tobin Davis9102cd12006-12-15 10:02:12 +01007064 [ALC885_MACPRO] = "macpro",
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007065 [ALC885_MB5] = "mb5",
Takashi Iwai87350ad2007-08-16 18:19:38 +02007066 [ALC885_MBP3] = "mbp3",
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007067 [ALC885_IMAC24] = "imac24",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007068 [ALC882_AUTO] = "auto",
7069};
7070
7071static struct snd_pci_quirk alc882_cfg_tbl[] = {
7072 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
Kailang Yang272a5272007-05-14 11:00:38 +02007073 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
Kailang Yangac8842a2007-09-20 12:51:39 +02007074 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
Takashi Iwai914759b2007-09-06 14:52:04 +02007075 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007076 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
Claudio Matsuokac5d9f1c2007-07-19 23:18:32 +02007077 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
Tobin Davis7b9470d2006-12-28 13:56:48 +01007078 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007079 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Jiang zhe44447042008-01-28 12:28:24 +01007080 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007081 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
7082 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
7083 SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
Kailang Yangdf694da2005-12-05 19:42:22 +01007084 {}
7085};
7086
7087static struct alc_config_preset alc882_presets[] = {
7088 [ALC882_3ST_DIG] = {
7089 .mixers = { alc882_base_mixer },
7090 .init_verbs = { alc882_init_verbs },
7091 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
7092 .dac_nids = alc882_dac_nids,
7093 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01007094 .dig_in_nid = ALC882_DIGIN_NID,
7095 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
7096 .channel_mode = alc882_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02007097 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01007098 .input_mux = &alc882_capture_source,
7099 },
7100 [ALC882_6ST_DIG] = {
7101 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
7102 .init_verbs = { alc882_init_verbs },
7103 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
7104 .dac_nids = alc882_dac_nids,
7105 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01007106 .dig_in_nid = ALC882_DIGIN_NID,
7107 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
7108 .channel_mode = alc882_sixstack_modes,
7109 .input_mux = &alc882_capture_source,
7110 },
Takashi Iwai4b146cb2006-07-28 14:42:36 +02007111 [ALC882_ARIMA] = {
7112 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
7113 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs },
7114 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
7115 .dac_nids = alc882_dac_nids,
7116 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
7117 .channel_mode = alc882_sixstack_modes,
7118 .input_mux = &alc882_capture_source,
7119 },
Kailang Yangbdd148a2007-05-08 15:19:08 +02007120 [ALC882_W2JC] = {
7121 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
7122 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
7123 alc880_gpio1_init_verbs },
7124 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
7125 .dac_nids = alc882_dac_nids,
7126 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
7127 .channel_mode = alc880_threestack_modes,
7128 .need_dac_fix = 1,
7129 .input_mux = &alc882_capture_source,
7130 .dig_out_nid = ALC882_DIGOUT_NID,
7131 },
Takashi Iwai87350ad2007-08-16 18:19:38 +02007132 [ALC885_MBP3] = {
7133 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
7134 .init_verbs = { alc885_mbp3_init_verbs,
7135 alc880_gpio1_init_verbs },
7136 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
7137 .dac_nids = alc882_dac_nids,
7138 .channel_mode = alc885_mbp_6ch_modes,
7139 .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes),
7140 .input_mux = &alc882_capture_source,
7141 .dig_out_nid = ALC882_DIGOUT_NID,
7142 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007143 .unsol_event = alc_automute_amp_unsol_event,
7144 .init_hook = alc885_mbp3_init_hook,
Takashi Iwai87350ad2007-08-16 18:19:38 +02007145 },
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007146 [ALC885_MB5] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007147 .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007148 .init_verbs = { alc885_mb5_init_verbs,
7149 alc880_gpio1_init_verbs },
7150 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
7151 .dac_nids = alc882_dac_nids,
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007152 .channel_mode = alc885_mb5_6ch_modes,
7153 .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007154 .input_mux = &mb5_capture_source,
7155 .dig_out_nid = ALC882_DIGOUT_NID,
7156 .dig_in_nid = ALC882_DIGIN_NID,
7157 },
Tobin Davis9102cd12006-12-15 10:02:12 +01007158 [ALC885_MACPRO] = {
7159 .mixers = { alc882_macpro_mixer },
7160 .init_verbs = { alc882_macpro_init_verbs },
7161 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
7162 .dac_nids = alc882_dac_nids,
7163 .dig_out_nid = ALC882_DIGOUT_NID,
7164 .dig_in_nid = ALC882_DIGIN_NID,
7165 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
7166 .channel_mode = alc882_ch_modes,
7167 .input_mux = &alc882_capture_source,
Takashi Iwai7debbe52007-08-16 15:01:03 +02007168 .init_hook = alc885_macpro_init_hook,
Tobin Davis9102cd12006-12-15 10:02:12 +01007169 },
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007170 [ALC885_IMAC24] = {
7171 .mixers = { alc885_imac24_mixer },
7172 .init_verbs = { alc885_imac24_init_verbs },
7173 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
7174 .dac_nids = alc882_dac_nids,
7175 .dig_out_nid = ALC882_DIGOUT_NID,
7176 .dig_in_nid = ALC882_DIGIN_NID,
7177 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
7178 .channel_mode = alc882_ch_modes,
7179 .input_mux = &alc882_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007180 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai7debbe52007-08-16 15:01:03 +02007181 .init_hook = alc885_imac24_init_hook,
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007182 },
Kailang Yang272a5272007-05-14 11:00:38 +02007183 [ALC882_TARGA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007184 .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
Kailang Yang272a5272007-05-14 11:00:38 +02007185 .init_verbs = { alc882_init_verbs, alc882_targa_verbs},
7186 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
7187 .dac_nids = alc882_dac_nids,
7188 .dig_out_nid = ALC882_DIGOUT_NID,
7189 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
7190 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01007191 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02007192 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
7193 .channel_mode = alc882_3ST_6ch_modes,
7194 .need_dac_fix = 1,
7195 .input_mux = &alc882_capture_source,
7196 .unsol_event = alc882_targa_unsol_event,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007197 .init_hook = alc882_targa_init_hook,
Kailang Yang272a5272007-05-14 11:00:38 +02007198 },
7199 [ALC882_ASUS_A7J] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007200 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
Kailang Yang272a5272007-05-14 11:00:38 +02007201 .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs},
7202 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
7203 .dac_nids = alc882_dac_nids,
7204 .dig_out_nid = ALC882_DIGOUT_NID,
7205 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
7206 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01007207 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02007208 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
7209 .channel_mode = alc882_3ST_6ch_modes,
7210 .need_dac_fix = 1,
7211 .input_mux = &alc882_capture_source,
Kailang Yangea1fb292008-08-26 12:58:38 +02007212 },
Takashi Iwai914759b2007-09-06 14:52:04 +02007213 [ALC882_ASUS_A7M] = {
7214 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
7215 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
7216 alc880_gpio1_init_verbs,
7217 alc882_asus_a7m_verbs },
7218 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
7219 .dac_nids = alc882_dac_nids,
7220 .dig_out_nid = ALC882_DIGOUT_NID,
7221 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
7222 .channel_mode = alc880_threestack_modes,
7223 .need_dac_fix = 1,
7224 .input_mux = &alc882_capture_source,
Kailang Yangea1fb292008-08-26 12:58:38 +02007225 },
Kailang Yangdf694da2005-12-05 19:42:22 +01007226};
7227
7228
7229/*
Takashi Iwaif95474e2007-07-10 00:47:43 +02007230 * Pin config fixes
7231 */
Kailang Yangea1fb292008-08-26 12:58:38 +02007232enum {
Takashi Iwaif95474e2007-07-10 00:47:43 +02007233 PINFIX_ABIT_AW9D_MAX
7234};
7235
7236static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
7237 { 0x15, 0x01080104 }, /* side */
7238 { 0x16, 0x01011012 }, /* rear */
7239 { 0x17, 0x01016011 }, /* clfe */
7240 { }
7241};
7242
7243static const struct alc_pincfg *alc882_pin_fixes[] = {
7244 [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
7245};
7246
7247static struct snd_pci_quirk alc882_pinfix_tbl[] = {
7248 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
7249 {}
7250};
7251
7252/*
Kailang Yangdf694da2005-12-05 19:42:22 +01007253 * BIOS auto configuration
7254 */
7255static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
7256 hda_nid_t nid, int pin_type,
7257 int dac_idx)
7258{
7259 /* set as output */
7260 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007261 int idx;
7262
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007263 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01007264 if (spec->multiout.dac_nids[dac_idx] == 0x25)
7265 idx = 4;
7266 else
7267 idx = spec->multiout.dac_nids[dac_idx] - 2;
Kailang Yangdf694da2005-12-05 19:42:22 +01007268 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
7269
7270}
7271
7272static void alc882_auto_init_multi_out(struct hda_codec *codec)
7273{
7274 struct alc_spec *spec = codec->spec;
7275 int i;
7276
7277 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007278 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007279 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01007280 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007281 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007282 i);
Kailang Yangdf694da2005-12-05 19:42:22 +01007283 }
7284}
7285
7286static void alc882_auto_init_hp_out(struct hda_codec *codec)
7287{
7288 struct alc_spec *spec = codec->spec;
7289 hda_nid_t pin;
7290
Takashi Iwaieb06ed82006-09-20 17:10:27 +02007291 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007292 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007293 /* use dac 0 */
7294 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007295 pin = spec->autocfg.speaker_pins[0];
7296 if (pin)
7297 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +01007298}
7299
7300#define alc882_is_input_pin(nid) alc880_is_input_pin(nid)
7301#define ALC882_PIN_CD_NID ALC880_PIN_CD_NID
7302
7303static void alc882_auto_init_analog_input(struct hda_codec *codec)
7304{
7305 struct alc_spec *spec = codec->spec;
7306 int i;
7307
7308 for (i = 0; i < AUTO_PIN_LAST; i++) {
7309 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai7194cae2008-03-06 16:58:17 +01007310 if (!nid)
7311 continue;
Takashi Iwai23f0c042009-02-26 13:03:58 +01007312 alc_set_input_pin(codec, nid, AUTO_PIN_FRONT_MIC /*i*/);
Takashi Iwai7194cae2008-03-06 16:58:17 +01007313 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
7314 snd_hda_codec_write(codec, nid, 0,
7315 AC_VERB_SET_AMP_GAIN_MUTE,
7316 AMP_OUT_MUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +01007317 }
7318}
7319
Takashi Iwaif511b012008-08-15 16:46:42 +02007320static void alc882_auto_init_input_src(struct hda_codec *codec)
7321{
7322 struct alc_spec *spec = codec->spec;
Takashi Iwaif511b012008-08-15 16:46:42 +02007323 int c;
7324
7325 for (c = 0; c < spec->num_adc_nids; c++) {
7326 hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
7327 hda_nid_t nid = spec->capsrc_nids[c];
Herton Ronaldo Krzesinskib98b7b32009-01-29 13:18:31 -02007328 unsigned int mux_idx;
7329 const struct hda_input_mux *imux;
Takashi Iwaif511b012008-08-15 16:46:42 +02007330 int conns, mute, idx, item;
7331
7332 conns = snd_hda_get_connections(codec, nid, conn_list,
7333 ARRAY_SIZE(conn_list));
7334 if (conns < 0)
7335 continue;
Herton Ronaldo Krzesinskib98b7b32009-01-29 13:18:31 -02007336 mux_idx = c >= spec->num_mux_defs ? 0 : c;
7337 imux = &spec->input_mux[mux_idx];
Takashi Iwaif511b012008-08-15 16:46:42 +02007338 for (idx = 0; idx < conns; idx++) {
7339 /* if the current connection is the selected one,
7340 * unmute it as default - otherwise mute it
7341 */
7342 mute = AMP_IN_MUTE(idx);
7343 for (item = 0; item < imux->num_items; item++) {
7344 if (imux->items[item].index == idx) {
7345 if (spec->cur_mux[c] == item)
7346 mute = AMP_IN_UNMUTE(idx);
7347 break;
7348 }
7349 }
Herton Ronaldo Krzesinskib98b7b32009-01-29 13:18:31 -02007350 /* check if we have a selector or mixer
7351 * we could check for the widget type instead, but
7352 * just check for Amp-In presence (in case of mixer
7353 * without amp-in there is something wrong, this
7354 * function shouldn't be used or capsrc nid is wrong)
7355 */
7356 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
7357 snd_hda_codec_write(codec, nid, 0,
7358 AC_VERB_SET_AMP_GAIN_MUTE,
7359 mute);
7360 else if (mute != AMP_IN_MUTE(idx))
7361 snd_hda_codec_write(codec, nid, 0,
7362 AC_VERB_SET_CONNECT_SEL,
7363 idx);
Takashi Iwaif511b012008-08-15 16:46:42 +02007364 }
7365 }
7366}
7367
Takashi Iwai776e1842007-08-29 15:07:11 +02007368/* add mic boosts if needed */
7369static int alc_auto_add_mic_boost(struct hda_codec *codec)
7370{
7371 struct alc_spec *spec = codec->spec;
7372 int err;
7373 hda_nid_t nid;
7374
7375 nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01007376 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02007377 err = add_control(spec, ALC_CTL_WIDGET_VOL,
7378 "Mic Boost",
7379 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
7380 if (err < 0)
7381 return err;
7382 }
7383 nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01007384 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02007385 err = add_control(spec, ALC_CTL_WIDGET_VOL,
7386 "Front Mic Boost",
7387 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
7388 if (err < 0)
7389 return err;
7390 }
7391 return 0;
7392}
7393
Kailang Yangdf694da2005-12-05 19:42:22 +01007394/* almost identical with ALC880 parser... */
7395static int alc882_parse_auto_config(struct hda_codec *codec)
7396{
7397 struct alc_spec *spec = codec->spec;
7398 int err = alc880_parse_auto_config(codec);
7399
7400 if (err < 0)
7401 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02007402 else if (!err)
7403 return 0; /* no config found */
7404
7405 err = alc_auto_add_mic_boost(codec);
7406 if (err < 0)
7407 return err;
7408
7409 /* hack - override the init verbs */
7410 spec->init_verbs[0] = alc882_auto_init_verbs;
7411
7412 return 1; /* config found */
Kailang Yangdf694da2005-12-05 19:42:22 +01007413}
7414
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007415/* additional initialization for auto-configuration model */
7416static void alc882_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01007417{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007418 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007419 alc882_auto_init_multi_out(codec);
7420 alc882_auto_init_hp_out(codec);
7421 alc882_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +02007422 alc882_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007423 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02007424 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01007425}
7426
Takashi Iwai7943a8a2008-04-16 17:29:09 +02007427static int patch_alc883(struct hda_codec *codec); /* called in patch_alc882() */
7428
Linus Torvalds1da177e2005-04-16 15:20:36 -07007429static int patch_alc882(struct hda_codec *codec)
7430{
7431 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007432 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007433
Takashi Iwaie560d8d2005-09-09 14:21:46 +02007434 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007435 if (spec == NULL)
7436 return -ENOMEM;
7437
Linus Torvalds1da177e2005-04-16 15:20:36 -07007438 codec->spec = spec;
7439
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007440 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
7441 alc882_models,
7442 alc882_cfg_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007443
Kailang Yangdf694da2005-12-05 19:42:22 +01007444 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Tobin Davis081d17c2007-02-15 17:46:18 +01007445 /* Pick up systems that don't supply PCI SSID */
7446 switch (codec->subsystem_id) {
7447 case 0x106b0c00: /* Mac Pro */
7448 board_config = ALC885_MACPRO;
7449 break;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007450 case 0x106b1000: /* iMac 24 */
Peter Korsgaardf3911c52008-09-27 09:13:45 +02007451 case 0x106b2800: /* AppleTV */
Mark Eggleston3077e442009-01-31 17:57:54 +01007452 case 0x106b3e00: /* iMac 24 Aluminium */
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007453 board_config = ALC885_IMAC24;
7454 break;
Luke Yelavich2d466382009-02-23 13:00:33 +11007455 case 0x106b00a0: /* MacBookPro3,1 - Another revision */
Takashi Iwaic7e07572008-06-26 14:42:51 +02007456 case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */
David Woodhouse9c95c432008-09-18 13:37:13 -07007457 case 0x106b00a4: /* MacbookPro4,1 */
Takashi Iwai87350ad2007-08-16 18:19:38 +02007458 case 0x106b2c00: /* Macbook Pro rev3 */
Torben Schulzeb4c41d2009-05-18 15:02:35 +02007459 /* Macbook 3.1 (0x106b3600) is handled by patch_alc883() */
Luke Yelavich2a884642009-01-28 15:58:38 +11007460 case 0x106b3800: /* MacbookPro4,1 - latter revision */
Takashi Iwai87350ad2007-08-16 18:19:38 +02007461 board_config = ALC885_MBP3;
7462 break;
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007463 case 0x106b3f00: /* Macbook 5,1 */
Takashi Iwai7442f9d2009-05-14 18:20:33 +02007464 case 0x106b4000: /* Macbook Pro 5,1 - FIXME: HP jack sense
7465 * seems not working, so apparently
7466 * no perfect solution yet
7467 */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007468 board_config = ALC885_MB5;
7469 break;
Tobin Davis081d17c2007-02-15 17:46:18 +01007470 default:
Takashi Iwai7943a8a2008-04-16 17:29:09 +02007471 /* ALC889A is handled better as ALC888-compatible */
Clive Messer669faba2008-09-30 15:49:13 +02007472 if (codec->revision_id == 0x100101 ||
7473 codec->revision_id == 0x100103) {
Takashi Iwai7943a8a2008-04-16 17:29:09 +02007474 alc_free(codec);
7475 return patch_alc883(codec);
7476 }
Takashi Iwai6c627f32009-05-18 12:33:36 +02007477 printk(KERN_INFO "hda_codec: Unknown model for %s, "
7478 "trying auto-probe from BIOS...\n",
7479 codec->chip_name);
Tobin Davis081d17c2007-02-15 17:46:18 +01007480 board_config = ALC882_AUTO;
7481 }
Kailang Yangdf694da2005-12-05 19:42:22 +01007482 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007483
Takashi Iwaif95474e2007-07-10 00:47:43 +02007484 alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
7485
Kailang Yangdf694da2005-12-05 19:42:22 +01007486 if (board_config == ALC882_AUTO) {
7487 /* automatic parse from the BIOS config */
7488 err = alc882_parse_auto_config(codec);
7489 if (err < 0) {
7490 alc_free(codec);
7491 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007492 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007493 printk(KERN_INFO
7494 "hda_codec: Cannot set up configuration "
7495 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01007496 board_config = ALC882_3ST_DIG;
7497 }
7498 }
7499
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09007500 err = snd_hda_attach_beep_device(codec, 0x1);
7501 if (err < 0) {
7502 alc_free(codec);
7503 return err;
7504 }
7505
Kailang Yangdf694da2005-12-05 19:42:22 +01007506 if (board_config != ALC882_AUTO)
7507 setup_preset(spec, &alc882_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007508
Kailang Yangdf694da2005-12-05 19:42:22 +01007509 spec->stream_analog_playback = &alc882_pcm_analog_playback;
7510 spec->stream_analog_capture = &alc882_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01007511 /* FIXME: setup DAC5 */
7512 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
7513 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007514
Kailang Yangdf694da2005-12-05 19:42:22 +01007515 spec->stream_digital_playback = &alc882_pcm_digital_playback;
7516 spec->stream_digital_capture = &alc882_pcm_digital_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007517
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02007518 spec->capture_style = CAPT_MIX; /* matrix-style capture */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007519 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +01007520 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01007521 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007522 /* get type */
7523 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +01007524 if (wcap != AC_WID_AUD_IN) {
7525 spec->adc_nids = alc882_adc_nids_alt;
7526 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt);
Takashi Iwaie1406342008-02-11 18:32:32 +01007527 spec->capsrc_nids = alc882_capsrc_nids_alt;
Kailang Yangdf694da2005-12-05 19:42:22 +01007528 } else {
7529 spec->adc_nids = alc882_adc_nids;
7530 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +01007531 spec->capsrc_nids = alc882_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +01007532 }
7533 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007534 set_capture_mixer(spec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007535 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007536
Takashi Iwai2134ea42008-01-10 16:53:55 +01007537 spec->vmaster_nid = 0x0c;
7538
Linus Torvalds1da177e2005-04-16 15:20:36 -07007539 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01007540 if (board_config == ALC882_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007541 spec->init_hook = alc882_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02007542#ifdef CONFIG_SND_HDA_POWER_SAVE
7543 if (!spec->loopback.amplist)
7544 spec->loopback.amplist = alc882_loopbacks;
7545#endif
Takashi Iwaidaead532008-11-28 12:55:36 +01007546 codec->proc_widget_hook = print_realtek_coef;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007547
7548 return 0;
7549}
7550
7551/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007552 * ALC883 support
7553 *
7554 * ALC883 is almost identical with ALC880 but has cleaner and more flexible
7555 * configuration. Each pin widget can choose any input DACs and a mixer.
7556 * Each ADC is connected from a mixer of all inputs. This makes possible
7557 * 6-channel independent captures.
7558 *
7559 * In addition, an independent DAC for the multi-playback (not used in this
7560 * driver yet).
7561 */
7562#define ALC883_DIGOUT_NID 0x06
7563#define ALC883_DIGIN_NID 0x0a
7564
Wu Fengguang3ab90932008-11-17 09:51:09 +01007565#define ALC1200_DIGOUT_NID 0x10
7566
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007567static hda_nid_t alc883_dac_nids[4] = {
7568 /* front, rear, clfe, rear_surr */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01007569 0x02, 0x03, 0x04, 0x05
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007570};
7571
7572static hda_nid_t alc883_adc_nids[2] = {
7573 /* ADC1-2 */
7574 0x08, 0x09,
7575};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007576
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007577static hda_nid_t alc883_adc_nids_alt[1] = {
7578 /* ADC1 */
7579 0x08,
7580};
7581
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08007582static hda_nid_t alc883_adc_nids_rev[2] = {
7583 /* ADC2-1 */
7584 0x09, 0x08
7585};
7586
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02007587#define alc889_adc_nids alc880_adc_nids
7588
Takashi Iwaie1406342008-02-11 18:32:32 +01007589static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 };
7590
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08007591static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
7592
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02007593#define alc889_capsrc_nids alc882_capsrc_nids
7594
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007595/* input MUX */
7596/* FIXME: should be a matrix-type input source selection */
7597
7598static struct hda_input_mux alc883_capture_source = {
7599 .num_items = 4,
7600 .items = {
7601 { "Mic", 0x0 },
7602 { "Front Mic", 0x1 },
7603 { "Line", 0x2 },
7604 { "CD", 0x4 },
7605 },
7606};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007607
Jiang zhe17bba1b2008-06-04 12:11:07 +02007608static struct hda_input_mux alc883_3stack_6ch_intel = {
7609 .num_items = 4,
7610 .items = {
7611 { "Mic", 0x1 },
7612 { "Front Mic", 0x0 },
7613 { "Line", 0x2 },
7614 { "CD", 0x4 },
7615 },
7616};
7617
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007618static struct hda_input_mux alc883_lenovo_101e_capture_source = {
7619 .num_items = 2,
7620 .items = {
7621 { "Mic", 0x1 },
7622 { "Line", 0x2 },
7623 },
7624};
7625
Kailang Yang272a5272007-05-14 11:00:38 +02007626static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
7627 .num_items = 4,
7628 .items = {
7629 { "Mic", 0x0 },
7630 { "iMic", 0x1 },
7631 { "Line", 0x2 },
7632 { "CD", 0x4 },
7633 },
7634};
7635
Jiang zhefb97dc62008-03-06 11:07:11 +01007636static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
7637 .num_items = 2,
7638 .items = {
7639 { "Mic", 0x0 },
7640 { "Int Mic", 0x1 },
7641 },
7642};
7643
Kailang Yange2757d52008-08-26 13:17:46 +02007644static struct hda_input_mux alc883_lenovo_sky_capture_source = {
7645 .num_items = 3,
7646 .items = {
7647 { "Mic", 0x0 },
7648 { "Front Mic", 0x1 },
7649 { "Line", 0x4 },
7650 },
7651};
7652
7653static struct hda_input_mux alc883_asus_eee1601_capture_source = {
7654 .num_items = 2,
7655 .items = {
7656 { "Mic", 0x0 },
7657 { "Line", 0x2 },
7658 },
7659};
7660
Torben Schulzeb4c41d2009-05-18 15:02:35 +02007661static struct hda_input_mux alc889A_mb31_capture_source = {
7662 .num_items = 2,
7663 .items = {
7664 { "Mic", 0x0 },
7665 /* Front Mic (0x01) unused */
7666 { "Line", 0x2 },
7667 /* Line 2 (0x03) unused */
7668 /* CD (0x04) unsused? */
7669 },
7670};
7671
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007672/*
7673 * 2ch mode
7674 */
7675static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
7676 { 2, NULL }
7677};
7678
7679/*
7680 * 2ch mode
7681 */
7682static struct hda_verb alc883_3ST_ch2_init[] = {
7683 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7684 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7685 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7686 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7687 { } /* end */
7688};
7689
7690/*
Tobin Davisb2011312007-09-17 12:45:11 +02007691 * 4ch mode
7692 */
7693static struct hda_verb alc883_3ST_ch4_init[] = {
7694 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7695 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7696 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7697 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7698 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7699 { } /* end */
7700};
7701
7702/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007703 * 6ch mode
7704 */
7705static struct hda_verb alc883_3ST_ch6_init[] = {
7706 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7707 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7708 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7709 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7710 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7711 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7712 { } /* end */
7713};
7714
Tobin Davisb2011312007-09-17 12:45:11 +02007715static struct hda_channel_mode alc883_3ST_6ch_modes[3] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007716 { 2, alc883_3ST_ch2_init },
Tobin Davisb2011312007-09-17 12:45:11 +02007717 { 4, alc883_3ST_ch4_init },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007718 { 6, alc883_3ST_ch6_init },
7719};
7720
7721/*
Jiang zhe17bba1b2008-06-04 12:11:07 +02007722 * 2ch mode
7723 */
7724static struct hda_verb alc883_3ST_ch2_intel_init[] = {
7725 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7726 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7727 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7728 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7729 { } /* end */
7730};
7731
7732/*
7733 * 4ch mode
7734 */
7735static struct hda_verb alc883_3ST_ch4_intel_init[] = {
7736 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7737 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7738 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7739 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7740 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7741 { } /* end */
7742};
7743
7744/*
7745 * 6ch mode
7746 */
7747static struct hda_verb alc883_3ST_ch6_intel_init[] = {
7748 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7749 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7750 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
7751 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7752 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7753 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7754 { } /* end */
7755};
7756
7757static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
7758 { 2, alc883_3ST_ch2_intel_init },
7759 { 4, alc883_3ST_ch4_intel_init },
7760 { 6, alc883_3ST_ch6_intel_init },
7761};
7762
7763/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007764 * 6ch mode
7765 */
7766static struct hda_verb alc883_sixstack_ch6_init[] = {
7767 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7768 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7769 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7770 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7771 { } /* end */
7772};
7773
7774/*
7775 * 8ch mode
7776 */
7777static struct hda_verb alc883_sixstack_ch8_init[] = {
7778 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7779 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7780 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7781 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7782 { } /* end */
7783};
7784
7785static struct hda_channel_mode alc883_sixstack_modes[2] = {
7786 { 6, alc883_sixstack_ch6_init },
7787 { 8, alc883_sixstack_ch8_init },
7788};
7789
Torben Schulzeb4c41d2009-05-18 15:02:35 +02007790/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
7791static struct hda_verb alc889A_mb31_ch2_init[] = {
7792 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
7793 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
7794 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
7795 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
7796 { } /* end */
7797};
7798
7799/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */
7800static struct hda_verb alc889A_mb31_ch4_init[] = {
7801 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
7802 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
7803 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
7804 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
7805 { } /* end */
7806};
7807
7808/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */
7809static struct hda_verb alc889A_mb31_ch5_init[] = {
7810 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */
7811 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
7812 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
7813 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
7814 { } /* end */
7815};
7816
7817/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */
7818static struct hda_verb alc889A_mb31_ch6_init[] = {
7819 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */
7820 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */
7821 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
7822 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
7823 { } /* end */
7824};
7825
7826static struct hda_channel_mode alc889A_mb31_6ch_modes[4] = {
7827 { 2, alc889A_mb31_ch2_init },
7828 { 4, alc889A_mb31_ch4_init },
7829 { 5, alc889A_mb31_ch5_init },
7830 { 6, alc889A_mb31_ch6_init },
7831};
7832
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007833static struct hda_verb alc883_medion_eapd_verbs[] = {
7834 /* eanable EAPD on medion laptop */
7835 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
7836 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
7837 { }
7838};
7839
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007840/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
7841 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
7842 */
7843
7844static struct snd_kcontrol_new alc883_base_mixer[] = {
7845 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7846 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7847 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7848 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7849 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7850 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7851 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7852 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7853 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
7854 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
7855 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7856 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7857 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7858 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7859 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7860 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007861 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007862 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7863 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007864 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007865 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007866 { } /* end */
7867};
7868
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007869static struct snd_kcontrol_new alc883_mitac_mixer[] = {
7870 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7871 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7872 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7873 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7874 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7875 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7876 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7877 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7878 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7879 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7880 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7881 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
7882 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007883 { } /* end */
7884};
7885
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007886static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01007887 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7888 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
7889 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7890 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
7891 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7892 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7893 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7894 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7895 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7896 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01007897 { } /* end */
7898};
7899
Jiang zhefb97dc62008-03-06 11:07:11 +01007900static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
7901 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7902 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
7903 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7904 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
7905 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7906 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7907 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7908 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7909 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7910 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01007911 { } /* end */
7912};
7913
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007914static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
7915 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7916 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7917 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7918 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7919 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7920 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7921 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7922 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007923 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007924 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7925 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007926 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007927 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007928 { } /* end */
7929};
7930
7931static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
7932 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7933 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7934 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7935 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7936 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7937 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7938 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7939 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7940 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7941 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7942 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7943 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7944 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7945 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007946 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007947 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7948 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007949 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007950 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007951 { } /* end */
7952};
7953
Jiang zhe17bba1b2008-06-04 12:11:07 +02007954static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
7955 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7956 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7957 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7958 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7959 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
7960 HDA_OUTPUT),
7961 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7962 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7963 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7964 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7965 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7966 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7967 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7968 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7969 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7970 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
7971 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7972 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7973 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
7974 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02007975 { } /* end */
7976};
7977
Takashi Iwaid1d985f2006-11-23 19:27:12 +01007978static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02007979 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007980 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007981 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007982 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007983 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7984 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007985 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7986 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007987 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7988 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7989 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7990 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7991 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7992 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007993 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007994 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7995 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007996 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007997 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007998 { } /* end */
7999};
8000
Kailang Yangccc656c2006-10-17 12:32:26 +02008001static struct snd_kcontrol_new alc883_tagra_mixer[] = {
8002 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8003 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8004 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8005 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8006 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8007 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8008 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8009 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8010 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8011 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8012 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8013 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8014 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8015 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008016 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008017 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008018 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008019};
Kailang Yangccc656c2006-10-17 12:32:26 +02008020
8021static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = {
8022 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8023 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8024 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8025 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8026 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8027 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008028 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008029 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe4383fae2008-04-14 12:58:57 +02008030 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8031 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8032 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008033 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008034};
Kailang Yangccc656c2006-10-17 12:32:26 +02008035
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008036static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
8037 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8038 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01008039 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8040 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008041 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8042 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8043 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8044 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008045 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008046};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008047
Kailang Yang272a5272007-05-14 11:00:38 +02008048static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
8049 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8050 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
8051 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8052 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8053 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8054 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8055 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8056 HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8057 HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008058 { } /* end */
8059};
8060
8061static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
8062 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8063 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8064 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8065 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8066 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8067 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8068 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8069 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8070 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008071 { } /* end */
Kailang Yangea1fb292008-08-26 12:58:38 +02008072};
Kailang Yang272a5272007-05-14 11:00:38 +02008073
Tobin Davis2880a862007-08-07 11:50:26 +02008074static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02008075 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8076 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02008077 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02008078 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8079 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02008080 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8081 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8082 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02008083 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02008084};
Tobin Davis2880a862007-08-07 11:50:26 +02008085
Kailang Yange2757d52008-08-26 13:17:46 +02008086static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
8087 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8088 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8089 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
8090 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
8091 HDA_CODEC_VOLUME_MONO("Center Playback Volume",
8092 0x0d, 1, 0x0, HDA_OUTPUT),
8093 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
8094 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
8095 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
8096 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8097 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02008098 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8099 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8100 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8101 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8102 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8103 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8104 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8105 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8106 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
8107 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02008108 { } /* end */
8109};
8110
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008111static struct snd_kcontrol_new alc889A_mb31_mixer[] = {
8112 /* Output mixers */
8113 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8114 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
8115 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
8116 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
8117 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00,
8118 HDA_OUTPUT),
8119 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT),
8120 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT),
8121 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT),
8122 /* Output switches */
8123 HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT),
8124 HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT),
8125 HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT),
8126 /* Boost mixers */
8127 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
8128 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
8129 /* Input mixers */
8130 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
8131 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
8132 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8133 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8134 { } /* end */
8135};
8136
Kailang Yange2757d52008-08-26 13:17:46 +02008137static struct hda_bind_ctls alc883_bind_cap_vol = {
8138 .ops = &snd_hda_bind_vol,
8139 .values = {
8140 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
8141 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
8142 0
8143 },
8144};
8145
8146static struct hda_bind_ctls alc883_bind_cap_switch = {
8147 .ops = &snd_hda_bind_sw,
8148 .values = {
8149 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
8150 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
8151 0
8152 },
8153};
8154
8155static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
8156 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8157 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8158 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8159 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8160 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8161 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8162 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8163 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008164 { } /* end */
8165};
8166
8167static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02008168 HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
8169 HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
8170 {
8171 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8172 /* .name = "Capture Source", */
8173 .name = "Input Source",
8174 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01008175 .info = alc_mux_enum_info,
8176 .get = alc_mux_enum_get,
8177 .put = alc_mux_enum_put,
Kailang Yange2757d52008-08-26 13:17:46 +02008178 },
8179 { } /* end */
8180};
8181
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008182static struct snd_kcontrol_new alc883_chmode_mixer[] = {
8183 {
8184 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8185 .name = "Channel Mode",
8186 .info = alc_ch_mode_info,
8187 .get = alc_ch_mode_get,
8188 .put = alc_ch_mode_put,
8189 },
8190 { } /* end */
8191};
8192
8193static struct hda_verb alc883_init_verbs[] = {
8194 /* ADC1: mute amp left and right */
Kailang Yange2757d52008-08-26 13:17:46 +02008195 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008196 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8197 /* ADC2: mute amp left and right */
8198 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8199 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8200 /* Front mixer: unmute input/output amp left and right (volume = 0) */
8201 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8202 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8203 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8204 /* Rear mixer */
8205 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8206 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8207 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8208 /* CLFE mixer */
8209 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8210 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8211 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8212 /* Side mixer */
8213 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8214 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8215 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8216
Takashi Iwaicb53c622007-08-10 17:21:45 +02008217 /* mute analog input loopbacks */
8218 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8219 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8220 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8221 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8222 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008223
8224 /* Front Pin: output 0 (0x0c) */
8225 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8226 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8227 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8228 /* Rear Pin: output 1 (0x0d) */
8229 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8230 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8231 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
8232 /* CLFE Pin: output 2 (0x0e) */
8233 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8234 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8235 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
8236 /* Side Pin: output 3 (0x0f) */
8237 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8238 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8239 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
8240 /* Mic (rear) pin: input vref at 80% */
8241 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8242 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8243 /* Front Mic pin: input vref at 80% */
8244 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8245 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8246 /* Line In pin: input */
8247 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8248 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8249 /* Line-2 In: Headphone output (output 0 - 0x0c) */
8250 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8251 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8252 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8253 /* CD pin widget for input */
8254 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8255
8256 /* FIXME: use matrix-type input source selection */
8257 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8258 /* Input mixer2 */
8259 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yange2757d52008-08-26 13:17:46 +02008260 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8261 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8262 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008263 /* Input mixer3 */
8264 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yange2757d52008-08-26 13:17:46 +02008265 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8266 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8267 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008268 { }
8269};
8270
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008271/* toggle speaker-output according to the hp-jack state */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008272static void alc883_mitac_init_hook(struct hda_codec *codec)
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008273{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008274 struct alc_spec *spec = codec->spec;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008275
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008276 spec->autocfg.hp_pins[0] = 0x15;
8277 spec->autocfg.speaker_pins[0] = 0x14;
8278 spec->autocfg.speaker_pins[1] = 0x17;
8279 alc_automute_amp(codec);
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008280}
8281
8282/* auto-toggle front mic */
8283/*
8284static void alc883_mitac_mic_automute(struct hda_codec *codec)
8285{
8286 unsigned int present;
8287 unsigned char bits;
8288
8289 present = snd_hda_codec_read(codec, 0x18, 0,
8290 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8291 bits = present ? HDA_AMP_MUTE : 0;
8292 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
8293}
8294*/
8295
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008296static struct hda_verb alc883_mitac_verbs[] = {
8297 /* HP */
8298 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8299 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8300 /* Subwoofer */
8301 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
8302 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8303
8304 /* enable unsolicited event */
8305 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8306 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
8307
8308 { } /* end */
8309};
8310
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008311static struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01008312 /* HP */
8313 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8314 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8315 /* Int speaker */
8316 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
8317 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8318
8319 /* enable unsolicited event */
8320 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008321 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01008322
8323 { } /* end */
8324};
8325
Jiang zhefb97dc62008-03-06 11:07:11 +01008326static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
8327 /* HP */
8328 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8329 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8330 /* Subwoofer */
8331 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
8332 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8333
8334 /* enable unsolicited event */
8335 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8336
8337 { } /* end */
8338};
8339
Kailang Yangccc656c2006-10-17 12:32:26 +02008340static struct hda_verb alc883_tagra_verbs[] = {
8341 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8342 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8343
8344 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8345 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008346
Kailang Yangccc656c2006-10-17 12:32:26 +02008347 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8348 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8349 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8350
8351 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008352 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
8353 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
8354 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
Kailang Yangccc656c2006-10-17 12:32:26 +02008355
8356 { } /* end */
8357};
8358
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008359static struct hda_verb alc883_lenovo_101e_verbs[] = {
8360 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8361 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
8362 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
8363 { } /* end */
8364};
8365
Kailang Yang272a5272007-05-14 11:00:38 +02008366static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
8367 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8368 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8369 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8370 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8371 { } /* end */
8372};
8373
8374static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
8375 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8376 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8377 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8378 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
8379 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8380 { } /* end */
8381};
8382
Kailang Yang189609a2007-08-20 11:31:23 +02008383static struct hda_verb alc883_haier_w66_verbs[] = {
8384 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8385 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8386
8387 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8388
8389 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8390 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8391 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8392 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8393 { } /* end */
8394};
8395
Kailang Yange2757d52008-08-26 13:17:46 +02008396static struct hda_verb alc888_lenovo_sky_verbs[] = {
8397 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8398 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8399 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8400 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8401 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8402 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8403 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8404 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8405 { } /* end */
8406};
8407
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008408static struct hda_verb alc888_6st_dell_verbs[] = {
8409 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8410 { }
8411};
8412
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008413static void alc888_3st_hp_init_hook(struct hda_codec *codec)
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008414{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008415 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008416
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008417 spec->autocfg.hp_pins[0] = 0x1b;
8418 spec->autocfg.speaker_pins[0] = 0x14;
8419 spec->autocfg.speaker_pins[1] = 0x16;
8420 spec->autocfg.speaker_pins[2] = 0x18;
8421 alc_automute_amp(codec);
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008422}
8423
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008424static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008425 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01008426 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
8427 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008428 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008429 { } /* end */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008430};
8431
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008432/*
8433 * 2ch mode
8434 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008435static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008436 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
8437 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8438 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
8439 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008440 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008441};
8442
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008443/*
8444 * 4ch mode
8445 */
8446static struct hda_verb alc888_3st_hp_4ch_init[] = {
8447 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
8448 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8449 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8450 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8451 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
8452 { } /* end */
8453};
8454
8455/*
8456 * 6ch mode
8457 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008458static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008459 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8460 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008461 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008462 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8463 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008464 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
8465 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008466};
8467
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008468static struct hda_channel_mode alc888_3st_hp_modes[3] = {
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008469 { 2, alc888_3st_hp_2ch_init },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008470 { 4, alc888_3st_hp_4ch_init },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008471 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008472};
8473
Kailang Yang272a5272007-05-14 11:00:38 +02008474/* toggle front-jack and RCA according to the hp-jack state */
8475static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
8476{
8477 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02008478
Kailang Yang272a5272007-05-14 11:00:38 +02008479 present = snd_hda_codec_read(codec, 0x1b, 0,
8480 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02008481 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8482 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8483 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8484 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02008485}
8486
8487/* toggle RCA according to the front-jack state */
8488static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
8489{
8490 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02008491
Kailang Yang272a5272007-05-14 11:00:38 +02008492 present = snd_hda_codec_read(codec, 0x14, 0,
8493 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02008494 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8495 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02008496}
Takashi Iwai47fd8302007-08-10 17:11:07 +02008497
Kailang Yang272a5272007-05-14 11:00:38 +02008498static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
8499 unsigned int res)
8500{
8501 if ((res >> 26) == ALC880_HP_EVENT)
8502 alc888_lenovo_ms7195_front_automute(codec);
8503 if ((res >> 26) == ALC880_FRONT_EVENT)
8504 alc888_lenovo_ms7195_rca_automute(codec);
8505}
8506
8507static struct hda_verb alc883_medion_md2_verbs[] = {
8508 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8509 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8510
8511 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8512
8513 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8514 { } /* end */
8515};
8516
8517/* toggle speaker-output according to the hp-jack state */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008518static void alc883_medion_md2_init_hook(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +02008519{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008520 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02008521
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008522 spec->autocfg.hp_pins[0] = 0x14;
8523 spec->autocfg.speaker_pins[0] = 0x15;
8524 alc_automute_amp(codec);
Kailang Yang272a5272007-05-14 11:00:38 +02008525}
8526
Kailang Yangccc656c2006-10-17 12:32:26 +02008527/* toggle speaker-output according to the hp-jack state */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008528#define alc883_tagra_init_hook alc882_targa_init_hook
8529#define alc883_tagra_unsol_event alc882_targa_unsol_event
Jiang zhe368c7a92008-03-04 11:20:33 +01008530
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008531static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
8532{
8533 unsigned int present;
8534
8535 present = snd_hda_codec_read(codec, 0x18, 0,
8536 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8537 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
8538 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8539}
8540
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008541static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008542{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008543 struct alc_spec *spec = codec->spec;
8544
8545 spec->autocfg.hp_pins[0] = 0x15;
8546 spec->autocfg.speaker_pins[0] = 0x14;
8547 alc_automute_amp(codec);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008548 alc883_clevo_m720_mic_automute(codec);
8549}
8550
8551static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01008552 unsigned int res)
8553{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008554 switch (res >> 26) {
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008555 case ALC880_MIC_EVENT:
8556 alc883_clevo_m720_mic_automute(codec);
8557 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008558 default:
8559 alc_automute_amp_unsol_event(codec, res);
8560 break;
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008561 }
Jiang zhe368c7a92008-03-04 11:20:33 +01008562}
8563
Jiang zhefb97dc62008-03-06 11:07:11 +01008564/* toggle speaker-output according to the hp-jack state */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008565static void alc883_2ch_fujitsu_pi2515_init_hook(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01008566{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008567 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01008568
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008569 spec->autocfg.hp_pins[0] = 0x14;
8570 spec->autocfg.speaker_pins[0] = 0x15;
8571 alc_automute_amp(codec);
Jiang zhefb97dc62008-03-06 11:07:11 +01008572}
8573
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008574static void alc883_haier_w66_init_hook(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01008575{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008576 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01008577
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008578 spec->autocfg.hp_pins[0] = 0x1b;
8579 spec->autocfg.speaker_pins[0] = 0x14;
8580 alc_automute_amp(codec);
Kailang Yang189609a2007-08-20 11:31:23 +02008581}
8582
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008583static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
8584{
8585 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008586 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008587
8588 present = snd_hda_codec_read(codec, 0x14, 0,
8589 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02008590 bits = present ? HDA_AMP_MUTE : 0;
8591 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8592 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008593}
8594
8595static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
8596{
8597 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008598 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008599
8600 present = snd_hda_codec_read(codec, 0x1b, 0,
8601 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02008602 bits = present ? HDA_AMP_MUTE : 0;
8603 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8604 HDA_AMP_MUTE, bits);
8605 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8606 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008607}
8608
8609static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
8610 unsigned int res)
8611{
8612 if ((res >> 26) == ALC880_HP_EVENT)
8613 alc883_lenovo_101e_all_automute(codec);
8614 if ((res >> 26) == ALC880_FRONT_EVENT)
8615 alc883_lenovo_101e_ispeaker_automute(codec);
8616}
8617
Takashi Iwai676a9b52007-08-16 15:23:35 +02008618/* toggle speaker-output according to the hp-jack state */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008619static void alc883_acer_aspire_init_hook(struct hda_codec *codec)
Takashi Iwai676a9b52007-08-16 15:23:35 +02008620{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008621 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02008622
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008623 spec->autocfg.hp_pins[0] = 0x14;
8624 spec->autocfg.speaker_pins[0] = 0x15;
8625 spec->autocfg.speaker_pins[1] = 0x16;
8626 alc_automute_amp(codec);
Takashi Iwai676a9b52007-08-16 15:23:35 +02008627}
8628
Kailang Yangd1a991a2007-08-15 16:21:59 +02008629static struct hda_verb alc883_acer_eapd_verbs[] = {
8630 /* HP Pin: output 0 (0x0c) */
8631 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8632 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8633 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8634 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02008635 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8636 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02008637 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02008638 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
8639 /* eanable EAPD on medion laptop */
8640 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8641 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02008642 /* enable unsolicited event */
8643 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02008644 { }
8645};
8646
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008647static void alc888_6st_dell_init_hook(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008648{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008649 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02008650
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008651 spec->autocfg.hp_pins[0] = 0x1b;
8652 spec->autocfg.speaker_pins[0] = 0x14;
8653 spec->autocfg.speaker_pins[1] = 0x15;
8654 spec->autocfg.speaker_pins[2] = 0x16;
8655 spec->autocfg.speaker_pins[3] = 0x17;
8656 alc_automute_amp(codec);
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008657}
8658
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008659static void alc888_lenovo_sky_init_hook(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008660{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008661 struct alc_spec *spec = codec->spec;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008662
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008663 spec->autocfg.hp_pins[0] = 0x1b;
8664 spec->autocfg.speaker_pins[0] = 0x14;
8665 spec->autocfg.speaker_pins[1] = 0x15;
8666 spec->autocfg.speaker_pins[2] = 0x16;
8667 spec->autocfg.speaker_pins[3] = 0x17;
8668 spec->autocfg.speaker_pins[4] = 0x1a;
8669 alc_automute_amp(codec);
Kailang Yange2757d52008-08-26 13:17:46 +02008670}
8671
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008672/*
8673 * generic initialization of ADC, input mixers and output mixers
8674 */
8675static struct hda_verb alc883_auto_init_verbs[] = {
8676 /*
8677 * Unmute ADC0-2 and set the default input to mic-in
8678 */
8679 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8680 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8681 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8682 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8683
Takashi Iwaicb53c622007-08-10 17:21:45 +02008684 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008685 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008686 * Note: PASD motherboards uses the Line In 2 as the input for
8687 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008688 */
8689 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02008690 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8691 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8692 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8693 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8694 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008695
8696 /*
8697 * Set up output mixers (0x0c - 0x0f)
8698 */
8699 /* set vol=0 to output mixers */
8700 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8701 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8702 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8703 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8704 /* set up input amps for analog loopback */
8705 /* Amp Indices: DAC = 0, mixer = 1 */
8706 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8707 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8708 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8709 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8710 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8711 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8712 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8713 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8714 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8715 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8716
8717 /* FIXME: use matrix-type input source selection */
8718 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8719 /* Input mixer1 */
8720 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8721 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8722 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008723 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008724 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
8725 /* Input mixer2 */
8726 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8727 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8728 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008729 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Andy Shevchenkoe3cde642007-12-03 16:50:58 +01008730 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008731
8732 { }
8733};
8734
Kailang Yange2757d52008-08-26 13:17:46 +02008735static struct hda_verb alc888_asus_m90v_verbs[] = {
8736 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8737 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8738 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8739 /* enable unsolicited event */
8740 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8741 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
8742 { } /* end */
8743};
8744
8745static void alc883_nb_mic_automute(struct hda_codec *codec)
8746{
8747 unsigned int present;
8748
8749 present = snd_hda_codec_read(codec, 0x18, 0,
8750 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8751 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
8752 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
8753 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
8754 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
8755}
8756
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008757static void alc883_M90V_init_hook(struct hda_codec *codec)
Kailang Yange2757d52008-08-26 13:17:46 +02008758{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008759 struct alc_spec *spec = codec->spec;
Kailang Yange2757d52008-08-26 13:17:46 +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 alc_automute_pin(codec);
Kailang Yange2757d52008-08-26 13:17:46 +02008766}
8767
8768static void alc883_mode2_unsol_event(struct hda_codec *codec,
8769 unsigned int res)
8770{
8771 switch (res >> 26) {
Kailang Yange2757d52008-08-26 13:17:46 +02008772 case ALC880_MIC_EVENT:
8773 alc883_nb_mic_automute(codec);
8774 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008775 default:
8776 alc_sku_unsol_event(codec, res);
8777 break;
Kailang Yange2757d52008-08-26 13:17:46 +02008778 }
8779}
8780
8781static void alc883_mode2_inithook(struct hda_codec *codec)
8782{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008783 alc883_M90V_init_hook(codec);
Kailang Yange2757d52008-08-26 13:17:46 +02008784 alc883_nb_mic_automute(codec);
8785}
8786
8787static struct hda_verb alc888_asus_eee1601_verbs[] = {
8788 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8789 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8790 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8791 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8792 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8793 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
8794 {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
8795 /* enable unsolicited event */
8796 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8797 { } /* end */
8798};
8799
Kailang Yange2757d52008-08-26 13:17:46 +02008800static void alc883_eee1601_inithook(struct hda_codec *codec)
8801{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008802 struct alc_spec *spec = codec->spec;
8803
8804 spec->autocfg.hp_pins[0] = 0x14;
8805 spec->autocfg.speaker_pins[0] = 0x1b;
8806 alc_automute_pin(codec);
Kailang Yange2757d52008-08-26 13:17:46 +02008807}
8808
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008809static struct hda_verb alc889A_mb31_verbs[] = {
8810 /* Init rear pin (used as headphone output) */
8811 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */
8812 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */
8813 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8814 /* Init line pin (used as output in 4ch and 6ch mode) */
8815 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Connect to CLFE */
8816 /* Init line 2 pin (used as headphone out by default) */
8817 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Use as input */
8818 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */
8819 { } /* end */
8820};
8821
8822/* Mute speakers according to the headphone jack state */
8823static void alc889A_mb31_automute(struct hda_codec *codec)
8824{
8825 unsigned int present;
8826
8827 /* Mute only in 2ch or 4ch mode */
8828 if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0)
8829 == 0x00) {
8830 present = snd_hda_codec_read(codec, 0x15, 0,
8831 AC_VERB_GET_PIN_SENSE, 0) & AC_PINSENSE_PRESENCE;
8832 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8833 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8834 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8835 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8836 }
8837}
8838
8839static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
8840{
8841 if ((res >> 26) == ALC880_HP_EVENT)
8842 alc889A_mb31_automute(codec);
8843}
8844
Takashi Iwaicb53c622007-08-10 17:21:45 +02008845#ifdef CONFIG_SND_HDA_POWER_SAVE
8846#define alc883_loopbacks alc880_loopbacks
8847#endif
8848
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008849/* pcm configuration: identiacal with ALC880 */
8850#define alc883_pcm_analog_playback alc880_pcm_analog_playback
8851#define alc883_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +01008852#define alc883_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008853#define alc883_pcm_digital_playback alc880_pcm_digital_playback
8854#define alc883_pcm_digital_capture alc880_pcm_digital_capture
8855
8856/*
8857 * configuration and preset
8858 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008859static const char *alc883_models[ALC883_MODEL_LAST] = {
8860 [ALC883_3ST_2ch_DIG] = "3stack-dig",
8861 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
8862 [ALC883_3ST_6ch] = "3stack-6ch",
8863 [ALC883_6ST_DIG] = "6stack-dig",
8864 [ALC883_TARGA_DIG] = "targa-dig",
8865 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008866 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02008867 [ALC883_ACER_ASPIRE] = "acer-aspire",
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08008868 [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g",
Hector Martin3b315d72009-06-02 10:54:19 +02008869 [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008870 [ALC883_MEDION] = "medion",
Kailang Yang272a5272007-05-14 11:00:38 +02008871 [ALC883_MEDION_MD2] = "medion-md2",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008872 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008873 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02008874 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
8875 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yange2757d52008-08-26 13:17:46 +02008876 [ALC888_LENOVO_SKY] = "lenovo-sky",
Kailang Yang189609a2007-08-20 11:31:23 +02008877 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008878 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008879 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008880 [ALC883_MITAC] = "mitac",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008881 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +01008882 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08008883 [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
Jiang zhe17bba1b2008-06-04 12:11:07 +02008884 [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
Wu Fengguang3ab90932008-11-17 09:51:09 +01008885 [ALC1200_ASUS_P5Q] = "asus-p5q",
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008886 [ALC889A_MB31] = "mb31",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008887 [ALC883_AUTO] = "auto",
8888};
8889
8890static struct snd_pci_quirk alc883_cfg_tbl[] = {
8891 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008892 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
Takashi Iwai69e50282008-11-03 10:07:43 +01008893 SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
Takashi Iwai9b6682f2009-03-23 22:50:52 +01008894 SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008895 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
8896 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
Jaroslav Kysela0b18cb12008-07-28 17:07:07 +02008897 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08008898 SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
8899 ALC888_ACER_ASPIRE_4930G),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01008900 SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
8901 ALC888_ACER_ASPIRE_4930G),
Hector Martin3b315d72009-06-02 10:54:19 +02008902 SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
8903 ALC888_ACER_ASPIRE_8930G),
Takashi Iwaib3bdb302009-02-18 13:16:26 +01008904 SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC883_AUTO),
Takashi Iwai94683502009-02-13 09:31:20 +01008905 SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC883_AUTO),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01008906 SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
8907 ALC888_ACER_ASPIRE_4930G),
Juan Jesus Garcia de Soriacc374c42009-02-23 08:11:59 +01008908 SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
8909 ALC888_ACER_ASPIRE_4930G),
Takashi Iwai22b530e2009-05-13 11:32:52 +02008910 /* default Acer -- disabled as it causes more problems.
8911 * model=auto should work fine now
8912 */
8913 /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008914 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Tobin Davisfebe3372007-06-12 11:27:46 +02008915 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008916 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
8917 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +01008918 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Chris Bagwell06bf3e12009-01-01 10:32:08 +01008919 SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
Herton Ronaldo Krzesinski7ec30f02009-03-04 14:22:52 -03008920 SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
Kailang Yanga01c30c2008-10-15 11:14:58 +02008921 SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008922 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Mackenzie Morgan44a678d2009-02-10 17:13:43 +01008923 SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
Wu Fengguang3ab90932008-11-17 09:51:09 +01008924 SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
Kailang Yange2757d52008-08-26 13:17:46 +02008925 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
Travis Place97ec7102008-05-23 18:31:46 +02008926 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008927 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
Luke Yelavich2de686d2009-01-16 15:08:02 +11008928 SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008929 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
8930 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
Kailang Yange2757d52008-08-26 13:17:46 +02008931 SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008932 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Tobin Davis57b14f22007-04-18 23:05:36 +02008933 SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008934 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
8935 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
8936 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Jiang zhe4383fae2008-04-14 12:58:57 +02008937 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008938 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01008939 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008940 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
8941 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
8942 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
8943 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
8944 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
8945 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
8946 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
8947 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
8948 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008949 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
8950 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02008951 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Takashi Iwaiee095432008-11-25 15:03:38 +01008952 SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +01008953 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01008954 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02008955 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008956 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008957 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008958 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
8959 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
Takashi Iwaidea0a502009-02-09 17:14:52 +01008960 SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04008961 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008962 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Takashi Iwaibfb53032009-04-14 14:51:04 +02008963 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
Takashi Iwaif67d8172009-02-04 23:30:19 +01008964 ALC883_FUJITSU_PI2515),
Takashi Iwaibfb53032009-04-14 14:51:04 +02008965 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08008966 ALC888_FUJITSU_XA3530),
Kailang Yang272a5272007-05-14 11:00:38 +02008967 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02008968 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008969 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
8970 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yange2757d52008-08-26 13:17:46 +02008971 SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
Kailang Yang272a5272007-05-14 11:00:38 +02008972 SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
Takashi Iwai959973b2008-11-05 11:30:56 +01008973 SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01008974 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02008975 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008976 SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
8977 SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
Luke Yelavich2de686d2009-01-16 15:08:02 +11008978 SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
Wu Fengguang4b558992009-01-12 09:18:58 +08008979 SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC883_3ST_6ch_INTEL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008980 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008981 {}
8982};
8983
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08008984static hda_nid_t alc883_slave_dig_outs[] = {
8985 ALC1200_DIGOUT_NID, 0,
8986};
8987
Wu Fengguangb25c9da2009-02-06 15:02:27 +08008988static hda_nid_t alc1200_slave_dig_outs[] = {
8989 ALC883_DIGOUT_NID, 0,
8990};
8991
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008992static struct alc_config_preset alc883_presets[] = {
8993 [ALC883_3ST_2ch_DIG] = {
8994 .mixers = { alc883_3ST_2ch_mixer },
8995 .init_verbs = { alc883_init_verbs },
8996 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8997 .dac_nids = alc883_dac_nids,
8998 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008999 .dig_in_nid = ALC883_DIGIN_NID,
9000 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9001 .channel_mode = alc883_3ST_2ch_modes,
9002 .input_mux = &alc883_capture_source,
9003 },
9004 [ALC883_3ST_6ch_DIG] = {
9005 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9006 .init_verbs = { alc883_init_verbs },
9007 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9008 .dac_nids = alc883_dac_nids,
9009 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009010 .dig_in_nid = ALC883_DIGIN_NID,
9011 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9012 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02009013 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009014 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009015 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009016 [ALC883_3ST_6ch] = {
9017 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9018 .init_verbs = { alc883_init_verbs },
9019 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9020 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009021 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9022 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02009023 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009024 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009025 },
Jiang zhe17bba1b2008-06-04 12:11:07 +02009026 [ALC883_3ST_6ch_INTEL] = {
9027 .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
9028 .init_verbs = { alc883_init_verbs },
9029 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9030 .dac_nids = alc883_dac_nids,
9031 .dig_out_nid = ALC883_DIGOUT_NID,
9032 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08009033 .slave_dig_outs = alc883_slave_dig_outs,
Jiang zhe17bba1b2008-06-04 12:11:07 +02009034 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
9035 .channel_mode = alc883_3ST_6ch_intel_modes,
9036 .need_dac_fix = 1,
9037 .input_mux = &alc883_3stack_6ch_intel,
9038 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009039 [ALC883_6ST_DIG] = {
9040 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
9041 .init_verbs = { alc883_init_verbs },
9042 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9043 .dac_nids = alc883_dac_nids,
9044 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009045 .dig_in_nid = ALC883_DIGIN_NID,
9046 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9047 .channel_mode = alc883_sixstack_modes,
9048 .input_mux = &alc883_capture_source,
9049 },
Kailang Yangccc656c2006-10-17 12:32:26 +02009050 [ALC883_TARGA_DIG] = {
9051 .mixers = { alc883_tagra_mixer, alc883_chmode_mixer },
9052 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
9053 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9054 .dac_nids = alc883_dac_nids,
9055 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02009056 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9057 .channel_mode = alc883_3ST_6ch_modes,
9058 .need_dac_fix = 1,
9059 .input_mux = &alc883_capture_source,
9060 .unsol_event = alc883_tagra_unsol_event,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009061 .init_hook = alc883_tagra_init_hook,
Kailang Yangccc656c2006-10-17 12:32:26 +02009062 },
9063 [ALC883_TARGA_2ch_DIG] = {
9064 .mixers = { alc883_tagra_2ch_mixer},
9065 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
9066 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9067 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009068 .adc_nids = alc883_adc_nids_alt,
9069 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Kailang Yangccc656c2006-10-17 12:32:26 +02009070 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02009071 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9072 .channel_mode = alc883_3ST_2ch_modes,
9073 .input_mux = &alc883_capture_source,
9074 .unsol_event = alc883_tagra_unsol_event,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009075 .init_hook = alc883_tagra_init_hook,
Kailang Yangccc656c2006-10-17 12:32:26 +02009076 },
Vladimir Avdoninbab282b92006-08-22 13:31:58 +02009077 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02009078 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b92006-08-22 13:31:58 +02009079 /* On TravelMate laptops, GPIO 0 enables the internal speaker
9080 * and the headphone jack. Turn this on and rely on the
9081 * standard mute methods whenever the user wants to turn
9082 * these outputs off.
9083 */
9084 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
9085 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9086 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b92006-08-22 13:31:58 +02009087 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9088 .channel_mode = alc883_3ST_2ch_modes,
9089 .input_mux = &alc883_capture_source,
9090 },
Tobin Davis2880a862007-08-07 11:50:26 +02009091 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02009092 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +02009093 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +02009094 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9095 .dac_nids = alc883_dac_nids,
9096 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +02009097 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9098 .channel_mode = alc883_3ST_2ch_modes,
9099 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009100 .unsol_event = alc_automute_amp_unsol_event,
9101 .init_hook = alc883_acer_aspire_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +02009102 },
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009103 [ALC888_ACER_ASPIRE_4930G] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009104 .mixers = { alc888_base_mixer,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009105 alc883_chmode_mixer },
9106 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
9107 alc888_acer_aspire_4930g_verbs },
9108 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9109 .dac_nids = alc883_dac_nids,
9110 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
9111 .adc_nids = alc883_adc_nids_rev,
9112 .capsrc_nids = alc883_capsrc_nids_rev,
9113 .dig_out_nid = ALC883_DIGOUT_NID,
9114 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9115 .channel_mode = alc883_3ST_6ch_modes,
9116 .need_dac_fix = 1,
9117 .num_mux_defs =
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009118 ARRAY_SIZE(alc888_2_capture_sources),
9119 .input_mux = alc888_2_capture_sources,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009120 .unsol_event = alc_automute_amp_unsol_event,
9121 .init_hook = alc888_acer_aspire_4930g_init_hook,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009122 },
Hector Martin3b315d72009-06-02 10:54:19 +02009123 [ALC888_ACER_ASPIRE_8930G] = {
9124 .mixers = { alc888_base_mixer,
9125 alc883_chmode_mixer },
9126 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
Hector Martin018df412009-06-04 00:13:40 +02009127 alc889_acer_aspire_8930g_verbs },
Hector Martin3b315d72009-06-02 10:54:19 +02009128 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9129 .dac_nids = alc883_dac_nids,
Hector Martin018df412009-06-04 00:13:40 +02009130 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
9131 .adc_nids = alc889_adc_nids,
9132 .capsrc_nids = alc889_capsrc_nids,
Hector Martin3b315d72009-06-02 10:54:19 +02009133 .dig_out_nid = ALC883_DIGOUT_NID,
9134 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9135 .channel_mode = alc883_3ST_6ch_modes,
9136 .need_dac_fix = 1,
9137 .const_channel_count = 6,
9138 .num_mux_defs =
Hector Martin018df412009-06-04 00:13:40 +02009139 ARRAY_SIZE(alc889_capture_sources),
9140 .input_mux = alc889_capture_sources,
Hector Martin3b315d72009-06-02 10:54:19 +02009141 .unsol_event = alc_automute_amp_unsol_event,
Hector Martin018df412009-06-04 00:13:40 +02009142 .init_hook = alc889_acer_aspire_8930g_init_hook,
Hector Martin3b315d72009-06-02 10:54:19 +02009143 },
Tobin Davisc07584c2006-10-13 12:32:16 +02009144 [ALC883_MEDION] = {
9145 .mixers = { alc883_fivestack_mixer,
9146 alc883_chmode_mixer },
9147 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01009148 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +02009149 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9150 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009151 .adc_nids = alc883_adc_nids_alt,
9152 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Tobin Davisc07584c2006-10-13 12:32:16 +02009153 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9154 .channel_mode = alc883_sixstack_modes,
9155 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01009156 },
Kailang Yang272a5272007-05-14 11:00:38 +02009157 [ALC883_MEDION_MD2] = {
9158 .mixers = { alc883_medion_md2_mixer},
9159 .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
9160 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9161 .dac_nids = alc883_dac_nids,
9162 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02009163 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9164 .channel_mode = alc883_3ST_2ch_modes,
9165 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009166 .unsol_event = alc_automute_amp_unsol_event,
9167 .init_hook = alc883_medion_md2_init_hook,
Kailang Yangea1fb292008-08-26 12:58:38 +02009168 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01009169 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02009170 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01009171 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
9172 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9173 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01009174 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9175 .channel_mode = alc883_3ST_2ch_modes,
9176 .input_mux = &alc883_capture_source,
9177 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009178 [ALC883_CLEVO_M720] = {
9179 .mixers = { alc883_clevo_m720_mixer },
9180 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +01009181 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9182 .dac_nids = alc883_dac_nids,
9183 .dig_out_nid = ALC883_DIGOUT_NID,
9184 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9185 .channel_mode = alc883_3ST_2ch_modes,
9186 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009187 .unsol_event = alc883_clevo_m720_unsol_event,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009188 .init_hook = alc883_clevo_m720_init_hook,
Jiang zhe368c7a92008-03-04 11:20:33 +01009189 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009190 [ALC883_LENOVO_101E_2ch] = {
9191 .mixers = { alc883_lenovo_101e_2ch_mixer},
9192 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
9193 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9194 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009195 .adc_nids = alc883_adc_nids_alt,
9196 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009197 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9198 .channel_mode = alc883_3ST_2ch_modes,
9199 .input_mux = &alc883_lenovo_101e_capture_source,
9200 .unsol_event = alc883_lenovo_101e_unsol_event,
9201 .init_hook = alc883_lenovo_101e_all_automute,
9202 },
Kailang Yang272a5272007-05-14 11:00:38 +02009203 [ALC883_LENOVO_NB0763] = {
9204 .mixers = { alc883_lenovo_nb0763_mixer },
9205 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
9206 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9207 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02009208 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9209 .channel_mode = alc883_3ST_2ch_modes,
9210 .need_dac_fix = 1,
9211 .input_mux = &alc883_lenovo_nb0763_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009212 .unsol_event = alc_automute_amp_unsol_event,
9213 .init_hook = alc883_medion_md2_init_hook,
Kailang Yang272a5272007-05-14 11:00:38 +02009214 },
9215 [ALC888_LENOVO_MS7195_DIG] = {
9216 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9217 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
9218 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9219 .dac_nids = alc883_dac_nids,
9220 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02009221 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9222 .channel_mode = alc883_3ST_6ch_modes,
9223 .need_dac_fix = 1,
9224 .input_mux = &alc883_capture_source,
9225 .unsol_event = alc883_lenovo_ms7195_unsol_event,
9226 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +02009227 },
9228 [ALC883_HAIER_W66] = {
9229 .mixers = { alc883_tagra_2ch_mixer},
9230 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
9231 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9232 .dac_nids = alc883_dac_nids,
9233 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +02009234 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9235 .channel_mode = alc883_3ST_2ch_modes,
9236 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009237 .unsol_event = alc_automute_amp_unsol_event,
9238 .init_hook = alc883_haier_w66_init_hook,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01009239 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009240 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01009241 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009242 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009243 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9244 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009245 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
9246 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009247 .need_dac_fix = 1,
9248 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009249 .unsol_event = alc_automute_amp_unsol_event,
9250 .init_hook = alc888_3st_hp_init_hook,
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009251 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009252 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +01009253 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009254 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
9255 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9256 .dac_nids = alc883_dac_nids,
9257 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009258 .dig_in_nid = ALC883_DIGIN_NID,
9259 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9260 .channel_mode = alc883_sixstack_modes,
9261 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009262 .unsol_event = alc_automute_amp_unsol_event,
9263 .init_hook = alc888_6st_dell_init_hook,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009264 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009265 [ALC883_MITAC] = {
9266 .mixers = { alc883_mitac_mixer },
9267 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
9268 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9269 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009270 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9271 .channel_mode = alc883_3ST_2ch_modes,
9272 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009273 .unsol_event = alc_automute_amp_unsol_event,
9274 .init_hook = alc883_mitac_init_hook,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009275 },
Jiang zhefb97dc62008-03-06 11:07:11 +01009276 [ALC883_FUJITSU_PI2515] = {
9277 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
9278 .init_verbs = { alc883_init_verbs,
9279 alc883_2ch_fujitsu_pi2515_verbs},
9280 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9281 .dac_nids = alc883_dac_nids,
9282 .dig_out_nid = ALC883_DIGOUT_NID,
9283 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9284 .channel_mode = alc883_3ST_2ch_modes,
9285 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009286 .unsol_event = alc_automute_amp_unsol_event,
9287 .init_hook = alc883_2ch_fujitsu_pi2515_init_hook,
Jiang zhefb97dc62008-03-06 11:07:11 +01009288 },
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009289 [ALC888_FUJITSU_XA3530] = {
9290 .mixers = { alc888_base_mixer, alc883_chmode_mixer },
9291 .init_verbs = { alc883_init_verbs,
9292 alc888_fujitsu_xa3530_verbs },
9293 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9294 .dac_nids = alc883_dac_nids,
9295 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
9296 .adc_nids = alc883_adc_nids_rev,
9297 .capsrc_nids = alc883_capsrc_nids_rev,
9298 .dig_out_nid = ALC883_DIGOUT_NID,
9299 .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes),
9300 .channel_mode = alc888_4ST_8ch_intel_modes,
9301 .num_mux_defs =
9302 ARRAY_SIZE(alc888_2_capture_sources),
9303 .input_mux = alc888_2_capture_sources,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009304 .unsol_event = alc_automute_amp_unsol_event,
9305 .init_hook = alc888_fujitsu_xa3530_init_hook,
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009306 },
Kailang Yange2757d52008-08-26 13:17:46 +02009307 [ALC888_LENOVO_SKY] = {
9308 .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
9309 .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
9310 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9311 .dac_nids = alc883_dac_nids,
9312 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yange2757d52008-08-26 13:17:46 +02009313 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9314 .channel_mode = alc883_sixstack_modes,
9315 .need_dac_fix = 1,
9316 .input_mux = &alc883_lenovo_sky_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009317 .unsol_event = alc_automute_amp_unsol_event,
9318 .init_hook = alc888_lenovo_sky_init_hook,
Kailang Yange2757d52008-08-26 13:17:46 +02009319 },
9320 [ALC888_ASUS_M90V] = {
9321 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9322 .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
9323 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9324 .dac_nids = alc883_dac_nids,
9325 .dig_out_nid = ALC883_DIGOUT_NID,
9326 .dig_in_nid = ALC883_DIGIN_NID,
9327 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9328 .channel_mode = alc883_3ST_6ch_modes,
9329 .need_dac_fix = 1,
9330 .input_mux = &alc883_fujitsu_pi2515_capture_source,
9331 .unsol_event = alc883_mode2_unsol_event,
9332 .init_hook = alc883_mode2_inithook,
9333 },
9334 [ALC888_ASUS_EEE1601] = {
9335 .mixers = { alc883_asus_eee1601_mixer },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009336 .cap_mixer = alc883_asus_eee1601_cap_mixer,
Kailang Yange2757d52008-08-26 13:17:46 +02009337 .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
9338 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9339 .dac_nids = alc883_dac_nids,
9340 .dig_out_nid = ALC883_DIGOUT_NID,
9341 .dig_in_nid = ALC883_DIGIN_NID,
9342 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9343 .channel_mode = alc883_3ST_2ch_modes,
9344 .need_dac_fix = 1,
9345 .input_mux = &alc883_asus_eee1601_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009346 .unsol_event = alc_sku_unsol_event,
Kailang Yange2757d52008-08-26 13:17:46 +02009347 .init_hook = alc883_eee1601_inithook,
9348 },
Wu Fengguang3ab90932008-11-17 09:51:09 +01009349 [ALC1200_ASUS_P5Q] = {
9350 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
9351 .init_verbs = { alc883_init_verbs },
9352 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9353 .dac_nids = alc883_dac_nids,
9354 .dig_out_nid = ALC1200_DIGOUT_NID,
9355 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangb25c9da2009-02-06 15:02:27 +08009356 .slave_dig_outs = alc1200_slave_dig_outs,
Wu Fengguang3ab90932008-11-17 09:51:09 +01009357 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9358 .channel_mode = alc883_sixstack_modes,
9359 .input_mux = &alc883_capture_source,
9360 },
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009361 [ALC889A_MB31] = {
9362 .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer},
9363 .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs,
9364 alc880_gpio1_init_verbs },
9365 .adc_nids = alc883_adc_nids,
9366 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
9367 .dac_nids = alc883_dac_nids,
9368 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9369 .channel_mode = alc889A_mb31_6ch_modes,
9370 .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes),
9371 .input_mux = &alc889A_mb31_capture_source,
9372 .dig_out_nid = ALC883_DIGOUT_NID,
9373 .unsol_event = alc889A_mb31_unsol_event,
9374 .init_hook = alc889A_mb31_automute,
9375 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009376};
9377
9378
9379/*
9380 * BIOS auto configuration
9381 */
9382static void alc883_auto_set_output_and_unmute(struct hda_codec *codec,
9383 hda_nid_t nid, int pin_type,
9384 int dac_idx)
9385{
9386 /* set as output */
9387 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009388 int idx;
9389
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009390 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009391 if (spec->multiout.dac_nids[dac_idx] == 0x25)
9392 idx = 4;
9393 else
9394 idx = spec->multiout.dac_nids[dac_idx] - 2;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009395 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
9396
9397}
9398
9399static void alc883_auto_init_multi_out(struct hda_codec *codec)
9400{
9401 struct alc_spec *spec = codec->spec;
9402 int i;
9403
9404 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009405 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02009406 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009407 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02009408 alc883_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009409 i);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009410 }
9411}
9412
9413static void alc883_auto_init_hp_out(struct hda_codec *codec)
9414{
9415 struct alc_spec *spec = codec->spec;
9416 hda_nid_t pin;
9417
Takashi Iwaieb06ed82006-09-20 17:10:27 +02009418 pin = spec->autocfg.hp_pins[0];
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009419 if (pin) /* connect to front */
9420 /* use dac 0 */
9421 alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009422 pin = spec->autocfg.speaker_pins[0];
9423 if (pin)
9424 alc883_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009425}
9426
9427#define alc883_is_input_pin(nid) alc880_is_input_pin(nid)
9428#define ALC883_PIN_CD_NID ALC880_PIN_CD_NID
9429
9430static void alc883_auto_init_analog_input(struct hda_codec *codec)
9431{
9432 struct alc_spec *spec = codec->spec;
9433 int i;
9434
9435 for (i = 0; i < AUTO_PIN_LAST; i++) {
9436 hda_nid_t nid = spec->autocfg.input_pins[i];
9437 if (alc883_is_input_pin(nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +01009438 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +01009439 if (nid != ALC883_PIN_CD_NID &&
9440 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009441 snd_hda_codec_write(codec, nid, 0,
9442 AC_VERB_SET_AMP_GAIN_MUTE,
9443 AMP_OUT_MUTE);
9444 }
9445 }
9446}
9447
Takashi Iwaif511b012008-08-15 16:46:42 +02009448#define alc883_auto_init_input_src alc882_auto_init_input_src
9449
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009450/* almost identical with ALC880 parser... */
9451static int alc883_parse_auto_config(struct hda_codec *codec)
9452{
9453 struct alc_spec *spec = codec->spec;
9454 int err = alc880_parse_auto_config(codec);
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02009455 struct auto_pin_cfg *cfg = &spec->autocfg;
9456 int i;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009457
9458 if (err < 0)
9459 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02009460 else if (!err)
9461 return 0; /* no config found */
9462
9463 err = alc_auto_add_mic_boost(codec);
9464 if (err < 0)
9465 return err;
9466
9467 /* hack - override the init verbs */
9468 spec->init_verbs[0] = alc883_auto_init_verbs;
Takashi Iwai776e1842007-08-29 15:07:11 +02009469
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02009470 /* setup input_mux for ALC889 */
9471 if (codec->vendor_id == 0x10ec0889) {
9472 /* digital-mic input pin is excluded in alc880_auto_create..()
9473 * because it's under 0x18
9474 */
9475 if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
9476 cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
9477 struct hda_input_mux *imux = &spec->private_imux[0];
9478 for (i = 1; i < 3; i++)
9479 memcpy(&spec->private_imux[i],
9480 &spec->private_imux[0],
9481 sizeof(spec->private_imux[0]));
9482 imux->items[imux->num_items].label = "Int DMic";
9483 imux->items[imux->num_items].index = 0x0b;
9484 imux->num_items++;
9485 spec->num_mux_defs = 3;
9486 spec->input_mux = spec->private_imux;
9487 }
9488 }
9489
Takashi Iwai776e1842007-08-29 15:07:11 +02009490 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009491}
9492
9493/* additional initialization for auto-configuration model */
9494static void alc883_auto_init(struct hda_codec *codec)
9495{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009496 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009497 alc883_auto_init_multi_out(codec);
9498 alc883_auto_init_hp_out(codec);
9499 alc883_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +02009500 alc883_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009501 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02009502 alc_inithook(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009503}
9504
9505static int patch_alc883(struct hda_codec *codec)
9506{
9507 struct alc_spec *spec;
9508 int err, board_config;
9509
9510 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
9511 if (spec == NULL)
9512 return -ENOMEM;
9513
9514 codec->spec = spec;
9515
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02009516 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
9517
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009518 board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST,
9519 alc883_models,
9520 alc883_cfg_tbl);
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009521 if (board_config < 0 || board_config >= ALC883_MODEL_LAST) {
9522 /* Pick up systems that don't supply PCI SSID */
9523 switch (codec->subsystem_id) {
9524 case 0x106b3600: /* Macbook 3.1 */
9525 board_config = ALC889A_MB31;
9526 break;
9527 default:
9528 printk(KERN_INFO
9529 "hda_codec: Unknown model for %s, trying "
9530 "auto-probe from BIOS...\n", codec->chip_name);
9531 board_config = ALC883_AUTO;
9532 }
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009533 }
9534
9535 if (board_config == ALC883_AUTO) {
9536 /* automatic parse from the BIOS config */
9537 err = alc883_parse_auto_config(codec);
9538 if (err < 0) {
9539 alc_free(codec);
9540 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009541 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009542 printk(KERN_INFO
9543 "hda_codec: Cannot set up configuration "
9544 "from BIOS. Using base mode...\n");
9545 board_config = ALC883_3ST_2ch_DIG;
9546 }
9547 }
9548
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09009549 err = snd_hda_attach_beep_device(codec, 0x1);
9550 if (err < 0) {
9551 alc_free(codec);
9552 return err;
9553 }
9554
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009555 if (board_config != ALC883_AUTO)
9556 setup_preset(spec, &alc883_presets[board_config]);
9557
Kailang Yang2f893282008-05-27 12:14:47 +02009558 switch (codec->vendor_id) {
9559 case 0x10ec0888:
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02009560 if (!spec->num_adc_nids) {
9561 spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
9562 spec->adc_nids = alc883_adc_nids;
9563 }
9564 if (!spec->capsrc_nids)
9565 spec->capsrc_nids = alc883_capsrc_nids;
9566 spec->capture_style = CAPT_MIX; /* matrix-style capture */
Takashi Iwai4a79ba342009-04-22 16:31:35 +02009567 spec->init_amp = ALC_INIT_DEFAULT; /* always initialize */
Kailang Yang2f893282008-05-27 12:14:47 +02009568 break;
9569 case 0x10ec0889:
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02009570 if (!spec->num_adc_nids) {
9571 spec->num_adc_nids = ARRAY_SIZE(alc889_adc_nids);
9572 spec->adc_nids = alc889_adc_nids;
9573 }
9574 if (!spec->capsrc_nids)
9575 spec->capsrc_nids = alc889_capsrc_nids;
9576 spec->capture_style = CAPT_1MUX_MIX; /* 1mux/Nmix-style
9577 capture */
Kailang Yang2f893282008-05-27 12:14:47 +02009578 break;
9579 default:
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02009580 if (!spec->num_adc_nids) {
9581 spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
9582 spec->adc_nids = alc883_adc_nids;
9583 }
9584 if (!spec->capsrc_nids)
9585 spec->capsrc_nids = alc883_capsrc_nids;
9586 spec->capture_style = CAPT_MIX; /* matrix-style capture */
Kailang Yang2f893282008-05-27 12:14:47 +02009587 break;
9588 }
9589
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009590 spec->stream_analog_playback = &alc883_pcm_analog_playback;
9591 spec->stream_analog_capture = &alc883_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01009592 spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009593
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009594 spec->stream_digital_playback = &alc883_pcm_digital_playback;
9595 spec->stream_digital_capture = &alc883_pcm_digital_capture;
9596
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009597 if (!spec->cap_mixer)
9598 set_capture_mixer(spec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01009599 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009600
Takashi Iwai2134ea42008-01-10 16:53:55 +01009601 spec->vmaster_nid = 0x0c;
9602
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009603 codec->patch_ops = alc_patch_ops;
9604 if (board_config == ALC883_AUTO)
9605 spec->init_hook = alc883_auto_init;
Kailang Yangf9423e72008-05-27 12:32:25 +02009606
Takashi Iwaicb53c622007-08-10 17:21:45 +02009607#ifdef CONFIG_SND_HDA_POWER_SAVE
9608 if (!spec->loopback.amplist)
9609 spec->loopback.amplist = alc883_loopbacks;
9610#endif
Takashi Iwaidaead532008-11-28 12:55:36 +01009611 codec->proc_widget_hook = print_realtek_coef;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009612
9613 return 0;
9614}
9615
9616/*
Kailang Yangdf694da2005-12-05 19:42:22 +01009617 * ALC262 support
9618 */
9619
9620#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
9621#define ALC262_DIGIN_NID ALC880_DIGIN_NID
9622
9623#define alc262_dac_nids alc260_dac_nids
9624#define alc262_adc_nids alc882_adc_nids
9625#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +01009626#define alc262_capsrc_nids alc882_capsrc_nids
9627#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +01009628
9629#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +01009630#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +01009631
Kailang Yang4e555fe2008-08-26 13:05:55 +02009632static hda_nid_t alc262_dmic_adc_nids[1] = {
9633 /* ADC0 */
9634 0x09
9635};
9636
9637static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
9638
Kailang Yangdf694da2005-12-05 19:42:22 +01009639static struct snd_kcontrol_new alc262_base_mixer[] = {
9640 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9641 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9642 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9643 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9644 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9645 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9646 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9647 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009648 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01009649 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9650 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009651 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01009652 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
9653 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9654 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
9655 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01009656 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +01009657};
9658
Takashi Iwaice875f02008-01-28 18:17:43 +01009659/* update HP, line and mono-out pins according to the master switch */
9660static void alc262_hp_master_update(struct hda_codec *codec)
9661{
9662 struct alc_spec *spec = codec->spec;
9663 int val = spec->master_sw;
9664
9665 /* HP & line-out */
9666 snd_hda_codec_write_cache(codec, 0x1b, 0,
9667 AC_VERB_SET_PIN_WIDGET_CONTROL,
9668 val ? PIN_HP : 0);
9669 snd_hda_codec_write_cache(codec, 0x15, 0,
9670 AC_VERB_SET_PIN_WIDGET_CONTROL,
9671 val ? PIN_HP : 0);
9672 /* mono (speaker) depending on the HP jack sense */
9673 val = val && !spec->jack_present;
9674 snd_hda_codec_write_cache(codec, 0x16, 0,
9675 AC_VERB_SET_PIN_WIDGET_CONTROL,
9676 val ? PIN_OUT : 0);
9677}
9678
9679static void alc262_hp_bpc_automute(struct hda_codec *codec)
9680{
9681 struct alc_spec *spec = codec->spec;
9682 unsigned int presence;
9683 presence = snd_hda_codec_read(codec, 0x1b, 0,
9684 AC_VERB_GET_PIN_SENSE, 0);
9685 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
9686 alc262_hp_master_update(codec);
9687}
9688
9689static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
9690{
9691 if ((res >> 26) != ALC880_HP_EVENT)
9692 return;
9693 alc262_hp_bpc_automute(codec);
9694}
9695
9696static void alc262_hp_wildwest_automute(struct hda_codec *codec)
9697{
9698 struct alc_spec *spec = codec->spec;
9699 unsigned int presence;
9700 presence = snd_hda_codec_read(codec, 0x15, 0,
9701 AC_VERB_GET_PIN_SENSE, 0);
9702 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
9703 alc262_hp_master_update(codec);
9704}
9705
9706static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
9707 unsigned int res)
9708{
9709 if ((res >> 26) != ALC880_HP_EVENT)
9710 return;
9711 alc262_hp_wildwest_automute(codec);
9712}
9713
Takashi Iwaib72519b2009-05-08 14:31:55 +02009714#define alc262_hp_master_sw_get alc260_hp_master_sw_get
Takashi Iwaice875f02008-01-28 18:17:43 +01009715
9716static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
9717 struct snd_ctl_elem_value *ucontrol)
9718{
9719 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9720 struct alc_spec *spec = codec->spec;
9721 int val = !!*ucontrol->value.integer.value;
9722
9723 if (val == spec->master_sw)
9724 return 0;
9725 spec->master_sw = val;
9726 alc262_hp_master_update(codec);
9727 return 1;
9728}
9729
Takashi Iwaib72519b2009-05-08 14:31:55 +02009730#define ALC262_HP_MASTER_SWITCH \
9731 { \
9732 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
9733 .name = "Master Playback Switch", \
9734 .info = snd_ctl_boolean_mono_info, \
9735 .get = alc262_hp_master_sw_get, \
9736 .put = alc262_hp_master_sw_put, \
9737 }
9738
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009739static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +02009740 ALC262_HP_MASTER_SWITCH,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009741 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9742 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9743 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01009744 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
9745 HDA_OUTPUT),
9746 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
9747 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009748 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9749 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009750 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009751 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9752 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009753 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009754 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9755 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9756 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9757 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009758 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
9759 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
9760 { } /* end */
9761};
9762
Kailang Yangcd7509a2007-01-26 18:33:17 +01009763static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +02009764 ALC262_HP_MASTER_SWITCH,
Kailang Yangcd7509a2007-01-26 18:33:17 +01009765 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9766 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9767 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9768 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01009769 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
9770 HDA_OUTPUT),
9771 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
9772 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009773 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
9774 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009775 HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009776 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
9777 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
9778 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9779 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009780 { } /* end */
9781};
9782
9783static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
9784 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9785 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009786 HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009787 { } /* end */
9788};
9789
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009790/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009791static void alc262_hp_t5735_init_hook(struct hda_codec *codec)
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009792{
9793 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009794
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009795 spec->autocfg.hp_pins[0] = 0x15;
9796 spec->autocfg.speaker_pins[0] = 0x0c; /* HACK: not actually a pin */
9797 alc_automute_amp(codec);
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009798}
9799
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009800static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +01009801 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9802 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009803 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9804 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9805 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9806 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9807 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9808 { } /* end */
9809};
9810
9811static struct hda_verb alc262_hp_t5735_verbs[] = {
9812 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9813 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9814
9815 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9816 { }
9817};
9818
Kailang Yang8c427222008-01-10 13:03:59 +01009819static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +01009820 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9821 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01009822 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
9823 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +01009824 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
9825 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
9826 { } /* end */
9827};
9828
9829static struct hda_verb alc262_hp_rp5700_verbs[] = {
9830 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9831 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9832 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9833 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9834 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9835 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9836 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9837 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9838 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
9839 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
9840 {}
9841};
9842
9843static struct hda_input_mux alc262_hp_rp5700_capture_source = {
9844 .num_items = 1,
9845 .items = {
9846 { "Line", 0x1 },
9847 },
9848};
9849
Takashi Iwai42171c12009-05-08 14:11:43 +02009850/* bind hp and internal speaker mute (with plug check) as master switch */
9851static void alc262_hippo_master_update(struct hda_codec *codec)
9852{
9853 struct alc_spec *spec = codec->spec;
9854 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
9855 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
9856 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
9857 unsigned int mute;
9858
9859 /* HP */
9860 mute = spec->master_sw ? 0 : HDA_AMP_MUTE;
9861 snd_hda_codec_amp_stereo(codec, hp_nid, HDA_OUTPUT, 0,
9862 HDA_AMP_MUTE, mute);
9863 /* mute internal speaker per jack sense */
9864 if (spec->jack_present)
9865 mute = HDA_AMP_MUTE;
9866 if (line_nid)
9867 snd_hda_codec_amp_stereo(codec, line_nid, HDA_OUTPUT, 0,
9868 HDA_AMP_MUTE, mute);
9869 if (speaker_nid && speaker_nid != line_nid)
9870 snd_hda_codec_amp_stereo(codec, speaker_nid, HDA_OUTPUT, 0,
9871 HDA_AMP_MUTE, mute);
9872}
9873
9874#define alc262_hippo_master_sw_get alc262_hp_master_sw_get
9875
9876static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol,
9877 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai0724ea22007-08-23 00:31:43 +02009878{
9879 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Takashi Iwai42171c12009-05-08 14:11:43 +02009880 struct alc_spec *spec = codec->spec;
9881 int val = !!*ucontrol->value.integer.value;
Takashi Iwai0724ea22007-08-23 00:31:43 +02009882
Takashi Iwai42171c12009-05-08 14:11:43 +02009883 if (val == spec->master_sw)
9884 return 0;
9885 spec->master_sw = val;
9886 alc262_hippo_master_update(codec);
9887 return 1;
Takashi Iwai0724ea22007-08-23 00:31:43 +02009888}
Takashi Iwai5b319542007-07-26 11:49:22 +02009889
Takashi Iwai42171c12009-05-08 14:11:43 +02009890#define ALC262_HIPPO_MASTER_SWITCH \
9891 { \
9892 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
9893 .name = "Master Playback Switch", \
9894 .info = snd_ctl_boolean_mono_info, \
9895 .get = alc262_hippo_master_sw_get, \
9896 .put = alc262_hippo_master_sw_put, \
9897 }
9898
9899static struct snd_kcontrol_new alc262_hippo_mixer[] = {
9900 ALC262_HIPPO_MASTER_SWITCH,
9901 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9902 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9903 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9904 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9905 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9906 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9907 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9908 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9909 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9910 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9911 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
9912 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9913 { } /* end */
9914};
9915
9916static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
9917 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9918 ALC262_HIPPO_MASTER_SWITCH,
9919 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9920 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9921 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9922 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9923 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9924 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9925 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9926 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9927 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9928 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
9929 { } /* end */
9930};
9931
9932/* mute/unmute internal speaker according to the hp jack and mute state */
9933static void alc262_hippo_automute(struct hda_codec *codec)
9934{
9935 struct alc_spec *spec = codec->spec;
9936 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
9937 unsigned int present;
9938
9939 /* need to execute and sync at first */
9940 snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0);
9941 present = snd_hda_codec_read(codec, hp_nid, 0,
9942 AC_VERB_GET_PIN_SENSE, 0);
9943 spec->jack_present = (present & 0x80000000) != 0;
9944 alc262_hippo_master_update(codec);
9945}
9946
9947static void alc262_hippo_unsol_event(struct hda_codec *codec, unsigned int res)
9948{
9949 if ((res >> 26) != ALC880_HP_EVENT)
9950 return;
9951 alc262_hippo_automute(codec);
9952}
9953
9954static void alc262_hippo_init_hook(struct hda_codec *codec)
9955{
9956 struct alc_spec *spec = codec->spec;
9957
9958 spec->autocfg.hp_pins[0] = 0x15;
9959 spec->autocfg.speaker_pins[0] = 0x14;
9960 alc262_hippo_automute(codec);
9961}
9962
9963static void alc262_hippo1_init_hook(struct hda_codec *codec)
9964{
9965 struct alc_spec *spec = codec->spec;
9966
9967 spec->autocfg.hp_pins[0] = 0x1b;
9968 spec->autocfg.speaker_pins[0] = 0x14;
9969 alc262_hippo_automute(codec);
9970}
9971
9972
Kailang Yang272a5272007-05-14 11:00:38 +02009973static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +02009974 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +02009975 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang272a5272007-05-14 11:00:38 +02009976 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9977 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9978 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9979 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9980 { } /* end */
9981};
9982
Kailang Yang83c34212007-07-05 11:43:05 +02009983static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +02009984 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9985 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang83c34212007-07-05 11:43:05 +02009986 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9987 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9988 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9989 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9990 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9991 { } /* end */
9992};
Kailang Yang272a5272007-05-14 11:00:38 +02009993
Tony Vroonba340e82009-02-02 19:01:30 +00009994static struct snd_kcontrol_new alc262_tyan_mixer[] = {
9995 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9996 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
9997 HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
9998 HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT),
9999 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10000 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10001 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10002 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10003 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10004 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10005 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10006 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
10007 { } /* end */
10008};
10009
10010static struct hda_verb alc262_tyan_verbs[] = {
10011 /* Headphone automute */
10012 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10013 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10014 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10015
10016 /* P11 AUX_IN, white 4-pin connector */
10017 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10018 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
10019 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
10020 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
10021
10022 {}
10023};
10024
10025/* unsolicited event for HP jack sensing */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010026static void alc262_tyan_init_hook(struct hda_codec *codec)
Tony Vroonba340e82009-02-02 19:01:30 +000010027{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010028 struct alc_spec *spec = codec->spec;
Tony Vroonba340e82009-02-02 19:01:30 +000010029
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010030 spec->autocfg.hp_pins[0] = 0x1b;
10031 spec->autocfg.speaker_pins[0] = 0x15;
10032 alc_automute_amp(codec);
Tony Vroonba340e82009-02-02 19:01:30 +000010033}
10034
Tony Vroonba340e82009-02-02 19:01:30 +000010035
Kailang Yangdf694da2005-12-05 19:42:22 +010010036#define alc262_capture_mixer alc882_capture_mixer
10037#define alc262_capture_alt_mixer alc882_capture_alt_mixer
10038
10039/*
10040 * generic initialization of ADC, input mixers and output mixers
10041 */
10042static struct hda_verb alc262_init_verbs[] = {
10043 /*
10044 * Unmute ADC0-2 and set the default input to mic-in
10045 */
10046 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
10047 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10048 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10049 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10050 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
10051 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10052
Takashi Iwaicb53c622007-08-10 17:21:45 +020010053 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010010054 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010055 * Note: PASD motherboards uses the Line In 2 as the input for
10056 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010010057 */
10058 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010059 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10060 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10061 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10062 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10063 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010010064
10065 /*
10066 * Set up output mixers (0x0c - 0x0e)
10067 */
10068 /* set vol=0 to output mixers */
10069 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10070 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10071 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10072 /* set up input amps for analog loopback */
10073 /* Amp Indices: DAC = 0, mixer = 1 */
10074 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10075 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10076 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10077 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10078 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10079 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10080
10081 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
10082 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
10083 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
10084 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10085 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10086 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10087
10088 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
10089 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
10090 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
10091 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
10092 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Kailang Yangea1fb292008-08-26 12:58:38 +020010093
Kailang Yangdf694da2005-12-05 19:42:22 +010010094 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
10095 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Kailang Yangea1fb292008-08-26 12:58:38 +020010096
Kailang Yangdf694da2005-12-05 19:42:22 +010010097 /* FIXME: use matrix-type input source selection */
10098 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10099 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10100 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10101 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10102 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10103 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10104 /* Input mixer2 */
10105 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10106 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10107 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10108 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10109 /* Input mixer3 */
10110 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10111 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10112 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010113 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +010010114
10115 { }
10116};
10117
Kailang Yang4e555fe2008-08-26 13:05:55 +020010118static struct hda_verb alc262_eapd_verbs[] = {
10119 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
10120 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
10121 { }
10122};
10123
Kailang Yangccc656c2006-10-17 12:32:26 +020010124static struct hda_verb alc262_hippo_unsol_verbs[] = {
10125 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10126 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10127 {}
10128};
10129
10130static struct hda_verb alc262_hippo1_unsol_verbs[] = {
10131 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
10132 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
10133 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
10134
10135 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10136 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10137 {}
10138};
10139
Kailang Yang272a5272007-05-14 11:00:38 +020010140static struct hda_verb alc262_sony_unsol_verbs[] = {
10141 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
10142 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10143 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
10144
10145 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10146 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +090010147 {}
Kailang Yang272a5272007-05-14 11:00:38 +020010148};
10149
Kailang Yang4e555fe2008-08-26 13:05:55 +020010150static struct hda_input_mux alc262_dmic_capture_source = {
10151 .num_items = 2,
10152 .items = {
10153 { "Int DMic", 0x9 },
10154 { "Mic", 0x0 },
10155 },
10156};
10157
10158static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
10159 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10160 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10161 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10162 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10163 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang4e555fe2008-08-26 13:05:55 +020010164 { } /* end */
10165};
10166
10167static struct hda_verb alc262_toshiba_s06_verbs[] = {
10168 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10169 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10170 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10171 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10172 {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
10173 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10174 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
10175 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10176 {}
10177};
10178
10179static void alc262_dmic_automute(struct hda_codec *codec)
10180{
10181 unsigned int present;
10182
10183 present = snd_hda_codec_read(codec, 0x18, 0,
10184 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
10185 snd_hda_codec_write(codec, 0x22, 0,
10186 AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x09);
10187}
10188
Kailang Yang4e555fe2008-08-26 13:05:55 +020010189
10190/* unsolicited event for HP jack sensing */
10191static void alc262_toshiba_s06_unsol_event(struct hda_codec *codec,
10192 unsigned int res)
10193{
Kailang Yang4e555fe2008-08-26 13:05:55 +020010194 if ((res >> 26) == ALC880_MIC_EVENT)
10195 alc262_dmic_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010196 else
10197 alc_sku_unsol_event(codec, res);
Kailang Yang4e555fe2008-08-26 13:05:55 +020010198}
10199
10200static void alc262_toshiba_s06_init_hook(struct hda_codec *codec)
10201{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010202 struct alc_spec *spec = codec->spec;
10203
10204 spec->autocfg.hp_pins[0] = 0x15;
10205 spec->autocfg.speaker_pins[0] = 0x14;
10206 alc_automute_pin(codec);
Kailang Yang4e555fe2008-08-26 13:05:55 +020010207 alc262_dmic_automute(codec);
10208}
10209
Takashi Iwai834be882006-03-01 14:16:17 +010010210/*
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010211 * nec model
10212 * 0x15 = headphone
10213 * 0x16 = internal speaker
10214 * 0x18 = external mic
10215 */
10216
10217static struct snd_kcontrol_new alc262_nec_mixer[] = {
10218 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
10219 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
10220
10221 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10222 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10223 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10224
10225 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
10226 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10227 { } /* end */
10228};
10229
10230static struct hda_verb alc262_nec_verbs[] = {
10231 /* Unmute Speaker */
10232 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10233
10234 /* Headphone */
10235 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10236 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10237
10238 /* External mic to headphone */
10239 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10240 /* External mic to speaker */
10241 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10242 {}
10243};
10244
10245/*
Takashi Iwai834be882006-03-01 14:16:17 +010010246 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +010010247 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
10248 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +010010249 */
10250
10251#define ALC_HP_EVENT 0x37
10252
10253static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
10254 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
10255 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +010010256 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
10257 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +010010258 {}
10259};
10260
Jiang zhe0e31daf2008-03-20 12:12:39 +010010261static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
10262 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
10263 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10264 {}
10265};
10266
Takashi Iwai834be882006-03-01 14:16:17 +010010267static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +020010268 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +010010269 .items = {
10270 { "Mic", 0x0 },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020010271 { "Int Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +010010272 { "CD", 0x4 },
10273 },
10274};
10275
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010276static struct hda_input_mux alc262_HP_capture_source = {
10277 .num_items = 5,
10278 .items = {
10279 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +020010280 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010281 { "Line", 0x2 },
10282 { "CD", 0x4 },
10283 { "AUX IN", 0x6 },
10284 },
10285};
10286
zhejiangaccbe492007-08-31 12:36:05 +020010287static struct hda_input_mux alc262_HP_D7000_capture_source = {
10288 .num_items = 4,
10289 .items = {
10290 { "Mic", 0x0 },
10291 { "Front Mic", 0x2 },
10292 { "Line", 0x1 },
10293 { "CD", 0x4 },
10294 },
10295};
10296
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010297/* mute/unmute internal speaker according to the hp jacks and mute state */
Takashi Iwai834be882006-03-01 14:16:17 +010010298static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
10299{
10300 struct alc_spec *spec = codec->spec;
10301 unsigned int mute;
10302
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010303 if (force || !spec->sense_updated) {
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010304 unsigned int present;
Takashi Iwai834be882006-03-01 14:16:17 +010010305 /* need to execute and sync at first */
10306 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010307 /* check laptop HP jack */
10308 present = snd_hda_codec_read(codec, 0x14, 0,
10309 AC_VERB_GET_PIN_SENSE, 0);
10310 /* need to execute and sync at first */
10311 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
10312 /* check docking HP jack */
10313 present |= snd_hda_codec_read(codec, 0x1b, 0,
10314 AC_VERB_GET_PIN_SENSE, 0);
10315 if (present & AC_PINSENSE_PRESENCE)
10316 spec->jack_present = 1;
10317 else
10318 spec->jack_present = 0;
Takashi Iwai834be882006-03-01 14:16:17 +010010319 spec->sense_updated = 1;
10320 }
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010321 /* unmute internal speaker only if both HPs are unplugged and
10322 * master switch is on
10323 */
10324 if (spec->jack_present)
10325 mute = HDA_AMP_MUTE;
10326 else
Takashi Iwai834be882006-03-01 14:16:17 +010010327 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010328 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
10329 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +010010330}
10331
10332/* unsolicited event for HP jack sensing */
10333static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
10334 unsigned int res)
10335{
10336 if ((res >> 26) != ALC_HP_EVENT)
10337 return;
10338 alc262_fujitsu_automute(codec, 1);
10339}
10340
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010341static void alc262_fujitsu_init_hook(struct hda_codec *codec)
10342{
10343 alc262_fujitsu_automute(codec, 1);
10344}
10345
Takashi Iwai834be882006-03-01 14:16:17 +010010346/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +020010347static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
10348 .ops = &snd_hda_bind_vol,
10349 .values = {
10350 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
10351 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
10352 0
10353 },
10354};
Takashi Iwai834be882006-03-01 14:16:17 +010010355
Jiang zhe0e31daf2008-03-20 12:12:39 +010010356/* mute/unmute internal speaker according to the hp jack and mute state */
10357static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
10358{
10359 struct alc_spec *spec = codec->spec;
10360 unsigned int mute;
10361
10362 if (force || !spec->sense_updated) {
10363 unsigned int present_int_hp;
10364 /* need to execute and sync at first */
10365 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
10366 present_int_hp = snd_hda_codec_read(codec, 0x1b, 0,
10367 AC_VERB_GET_PIN_SENSE, 0);
10368 spec->jack_present = (present_int_hp & 0x80000000) != 0;
10369 spec->sense_updated = 1;
10370 }
10371 if (spec->jack_present) {
10372 /* mute internal speaker */
10373 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10374 HDA_AMP_MUTE, HDA_AMP_MUTE);
10375 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
10376 HDA_AMP_MUTE, HDA_AMP_MUTE);
10377 } else {
10378 /* unmute internal speaker if necessary */
10379 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
10380 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10381 HDA_AMP_MUTE, mute);
10382 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
10383 HDA_AMP_MUTE, mute);
10384 }
10385}
10386
10387/* unsolicited event for HP jack sensing */
10388static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
10389 unsigned int res)
10390{
10391 if ((res >> 26) != ALC_HP_EVENT)
10392 return;
10393 alc262_lenovo_3000_automute(codec, 1);
10394}
10395
Takashi Iwai834be882006-03-01 14:16:17 +010010396/* bind hp and internal speaker mute (with plug check) */
10397static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
10398 struct snd_ctl_elem_value *ucontrol)
10399{
10400 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10401 long *valp = ucontrol->value.integer.value;
10402 int change;
10403
Tony Vroon5d9fab22008-03-14 17:09:18 +010010404 change = snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10405 HDA_AMP_MUTE,
10406 valp ? 0 : HDA_AMP_MUTE);
10407 change |= snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
10408 HDA_AMP_MUTE,
10409 valp ? 0 : HDA_AMP_MUTE);
10410
Takashi Iwai82beb8f2007-08-10 17:09:26 +020010411 if (change)
10412 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +010010413 return change;
10414}
10415
10416static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +020010417 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +010010418 {
10419 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10420 .name = "Master Playback Switch",
10421 .info = snd_hda_mixer_amp_switch_info,
10422 .get = snd_hda_mixer_amp_switch_get,
10423 .put = alc262_fujitsu_master_sw_put,
10424 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
10425 },
10426 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10427 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
10428 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10429 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10430 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai39d3ed32007-10-12 15:03:48 +020010431 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
10432 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
10433 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010010434 { } /* end */
10435};
10436
Jiang zhe0e31daf2008-03-20 12:12:39 +010010437/* bind hp and internal speaker mute (with plug check) */
10438static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
10439 struct snd_ctl_elem_value *ucontrol)
10440{
10441 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10442 long *valp = ucontrol->value.integer.value;
10443 int change;
10444
10445 change = snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
10446 HDA_AMP_MUTE,
10447 valp ? 0 : HDA_AMP_MUTE);
10448
10449 if (change)
10450 alc262_lenovo_3000_automute(codec, 0);
10451 return change;
10452}
10453
10454static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
10455 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
10456 {
10457 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10458 .name = "Master Playback Switch",
10459 .info = snd_hda_mixer_amp_switch_info,
10460 .get = snd_hda_mixer_amp_switch_get,
10461 .put = alc262_lenovo_3000_master_sw_put,
10462 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
10463 },
10464 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10465 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
10466 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10467 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10468 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10469 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
10470 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
10471 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
10472 { } /* end */
10473};
10474
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010475static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
10476 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai42171c12009-05-08 14:11:43 +020010477 ALC262_HIPPO_MASTER_SWITCH,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010478 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10479 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10480 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10481 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10482 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10483 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
10484 { } /* end */
10485};
10486
Takashi Iwai304dcaa2006-07-25 14:51:16 +020010487/* additional init verbs for Benq laptops */
10488static struct hda_verb alc262_EAPD_verbs[] = {
10489 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
10490 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
10491 {}
10492};
10493
Kailang Yang83c34212007-07-05 11:43:05 +020010494static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
10495 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10496 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10497
10498 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
10499 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
10500 {}
10501};
10502
Tobin Davisf651b502007-10-26 12:40:47 +020010503/* Samsung Q1 Ultra Vista model setup */
10504static struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010505 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10506 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020010507 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10508 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10509 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010510 HDA_CODEC_VOLUME("Headphone Mic Boost", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020010511 { } /* end */
10512};
10513
10514static struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010515 /* output mixer */
10516 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10517 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10518 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10519 /* speaker */
10520 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10521 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10522 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10523 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
10524 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +020010525 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010526 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10527 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10528 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10529 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10530 /* internal mic */
10531 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
10532 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10533 /* ADC, choose mic */
10534 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10535 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10536 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10537 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10538 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10539 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10540 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
10541 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
10542 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
10543 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +020010544 {}
10545};
10546
Tobin Davisf651b502007-10-26 12:40:47 +020010547/* mute/unmute internal speaker according to the hp jack and mute state */
10548static void alc262_ultra_automute(struct hda_codec *codec)
10549{
10550 struct alc_spec *spec = codec->spec;
10551 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +020010552
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010553 mute = 0;
10554 /* auto-mute only when HP is used as HP */
10555 if (!spec->cur_mux[0]) {
10556 unsigned int present;
10557 /* need to execute and sync at first */
10558 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
10559 present = snd_hda_codec_read(codec, 0x15, 0,
10560 AC_VERB_GET_PIN_SENSE, 0);
10561 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
10562 if (spec->jack_present)
10563 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +020010564 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010565 /* mute/unmute internal speaker */
10566 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10567 HDA_AMP_MUTE, mute);
10568 /* mute/unmute HP */
10569 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
10570 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +020010571}
10572
10573/* unsolicited event for HP jack sensing */
10574static void alc262_ultra_unsol_event(struct hda_codec *codec,
10575 unsigned int res)
10576{
10577 if ((res >> 26) != ALC880_HP_EVENT)
10578 return;
10579 alc262_ultra_automute(codec);
10580}
10581
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010582static struct hda_input_mux alc262_ultra_capture_source = {
10583 .num_items = 2,
10584 .items = {
10585 { "Mic", 0x1 },
10586 { "Headphone", 0x7 },
10587 },
10588};
10589
10590static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
10591 struct snd_ctl_elem_value *ucontrol)
10592{
10593 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10594 struct alc_spec *spec = codec->spec;
10595 int ret;
10596
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010010597 ret = alc_mux_enum_put(kcontrol, ucontrol);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010598 if (!ret)
10599 return 0;
10600 /* reprogram the HP pin as mic or HP according to the input source */
10601 snd_hda_codec_write_cache(codec, 0x15, 0,
10602 AC_VERB_SET_PIN_WIDGET_CONTROL,
10603 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
10604 alc262_ultra_automute(codec); /* mute/unmute HP */
10605 return ret;
10606}
10607
10608static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
10609 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
10610 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
10611 {
10612 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10613 .name = "Capture Source",
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010010614 .info = alc_mux_enum_info,
10615 .get = alc_mux_enum_get,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010616 .put = alc262_ultra_mux_enum_put,
10617 },
10618 { } /* end */
10619};
10620
Kailang Yangdf694da2005-12-05 19:42:22 +010010621/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010622static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
10623 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010010624{
10625 hda_nid_t nid;
10626 int err;
10627
10628 spec->multiout.num_dacs = 1; /* only use one dac */
10629 spec->multiout.dac_nids = spec->private_dac_nids;
10630 spec->multiout.dac_nids[0] = 2;
10631
10632 nid = cfg->line_out_pins[0];
10633 if (nid) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010634 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10635 "Front Playback Volume",
10636 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT));
10637 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010638 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010639 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10640 "Front Playback Switch",
10641 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
10642 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010643 return err;
10644 }
10645
Takashi Iwai82bc9552006-03-21 11:24:42 +010010646 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010010647 if (nid) {
10648 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010649 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10650 "Speaker Playback Volume",
10651 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
10652 HDA_OUTPUT));
10653 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010654 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010655 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10656 "Speaker Playback Switch",
10657 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
10658 HDA_OUTPUT));
10659 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010660 return err;
10661 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010662 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10663 "Speaker Playback Switch",
10664 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
10665 HDA_OUTPUT));
10666 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010667 return err;
10668 }
10669 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +020010670 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010010671 if (nid) {
10672 /* spec->multiout.hp_nid = 2; */
10673 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010674 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10675 "Headphone Playback Volume",
10676 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
10677 HDA_OUTPUT));
10678 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010679 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010680 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10681 "Headphone Playback Switch",
10682 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
10683 HDA_OUTPUT));
10684 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010685 return err;
10686 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010687 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10688 "Headphone Playback Switch",
10689 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
10690 HDA_OUTPUT));
10691 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010692 return err;
10693 }
10694 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010695 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +010010696}
10697
10698/* identical with ALC880 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010699#define alc262_auto_create_analog_input_ctls \
10700 alc880_auto_create_analog_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +010010701
10702/*
10703 * generic initialization of ADC, input mixers and output mixers
10704 */
10705static struct hda_verb alc262_volume_init_verbs[] = {
10706 /*
10707 * Unmute ADC0-2 and set the default input to mic-in
10708 */
10709 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
10710 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10711 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10712 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10713 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
10714 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10715
Takashi Iwaicb53c622007-08-10 17:21:45 +020010716 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010010717 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010718 * Note: PASD motherboards uses the Line In 2 as the input for
10719 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010010720 */
10721 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010722 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10723 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10724 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10725 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10726 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010010727
10728 /*
10729 * Set up output mixers (0x0c - 0x0f)
10730 */
10731 /* set vol=0 to output mixers */
10732 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10733 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10734 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yangea1fb292008-08-26 12:58:38 +020010735
Kailang Yangdf694da2005-12-05 19:42:22 +010010736 /* set up input amps for analog loopback */
10737 /* Amp Indices: DAC = 0, mixer = 1 */
10738 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10739 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10740 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10741 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10742 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10743 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10744
10745 /* FIXME: use matrix-type input source selection */
10746 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10747 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10748 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10749 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10750 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10751 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10752 /* Input mixer2 */
10753 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10754 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10755 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10756 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10757 /* Input mixer3 */
10758 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10759 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10760 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10761 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10762
10763 { }
10764};
10765
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010766static struct hda_verb alc262_HP_BPC_init_verbs[] = {
10767 /*
10768 * Unmute ADC0-2 and set the default input to mic-in
10769 */
10770 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
10771 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10772 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10773 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10774 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
10775 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10776
Takashi Iwaicb53c622007-08-10 17:21:45 +020010777 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010778 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010779 * Note: PASD motherboards uses the Line In 2 as the input for
10780 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010781 */
10782 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010783 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10784 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10785 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10786 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10787 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10788 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
10789 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Kailang Yangea1fb292008-08-26 12:58:38 +020010790
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010791 /*
10792 * Set up output mixers (0x0c - 0x0e)
10793 */
10794 /* set vol=0 to output mixers */
10795 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10796 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10797 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10798
10799 /* set up input amps for analog loopback */
10800 /* Amp Indices: DAC = 0, mixer = 1 */
10801 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10802 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10803 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10804 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10805 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10806 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10807
Takashi Iwaice875f02008-01-28 18:17:43 +010010808 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010809 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
10810 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
10811
10812 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10813 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10814
10815 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
10816 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10817
10818 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10819 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10820 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10821 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10822 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10823
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020010824 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010825 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10826 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020010827 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010828 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10829 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10830
10831
10832 /* FIXME: use matrix-type input source selection */
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020010833 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */
10834 /* Input mixer1: only unmute Mic */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010835 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020010836 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
10837 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10838 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10839 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10840 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
10841 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
10842 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
10843 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010844 /* Input mixer2 */
10845 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020010846 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
10847 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10848 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10849 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10850 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
10851 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
10852 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
10853 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010854 /* Input mixer3 */
10855 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020010856 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
10857 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10858 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10859 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10860 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
10861 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
10862 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
10863 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010864
Takashi Iwaice875f02008-01-28 18:17:43 +010010865 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10866
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010867 { }
10868};
10869
Kailang Yangcd7509a2007-01-26 18:33:17 +010010870static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
10871 /*
10872 * Unmute ADC0-2 and set the default input to mic-in
10873 */
10874 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
10875 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10876 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10877 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10878 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
10879 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10880
Takashi Iwaicb53c622007-08-10 17:21:45 +020010881 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +010010882 * mixer widget
10883 * Note: PASD motherboards uses the Line In 2 as the input for front
10884 * panel mic (mic 2)
10885 */
10886 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010887 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10888 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10889 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10890 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10891 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10892 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
10893 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
10894 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +010010895 /*
10896 * Set up output mixers (0x0c - 0x0e)
10897 */
10898 /* set vol=0 to output mixers */
10899 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10900 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10901 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10902
10903 /* set up input amps for analog loopback */
10904 /* Amp Indices: DAC = 0, mixer = 1 */
10905 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10906 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10907 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10908 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10909 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10910 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10911
10912
10913 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
10914 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
10915 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
10916 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
10917 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
10918 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
10919 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
10920
10921 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10922 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10923
10924 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
10925 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
10926
10927 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
10928 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10929 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10930 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
10931 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10932 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10933
10934 /* FIXME: use matrix-type input source selection */
10935 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10936 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10937 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
10938 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
10939 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
10940 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
10941 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
10942 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10943 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
10944 /* Input mixer2 */
10945 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10946 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10947 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10948 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10949 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10950 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10951 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
10952 /* Input mixer3 */
10953 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10954 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10955 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10956 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10957 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10958 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10959 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
10960
Takashi Iwaice875f02008-01-28 18:17:43 +010010961 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10962
Kailang Yangcd7509a2007-01-26 18:33:17 +010010963 { }
10964};
10965
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010966static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
10967
10968 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */
10969 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10970 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
10971
10972 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */
10973 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
10974 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
10975 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
10976
10977 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */
10978 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10979 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10980 {}
10981};
10982
10983
Takashi Iwaicb53c622007-08-10 17:21:45 +020010984#ifdef CONFIG_SND_HDA_POWER_SAVE
10985#define alc262_loopbacks alc880_loopbacks
10986#endif
10987
Kailang Yangdf694da2005-12-05 19:42:22 +010010988/* pcm configuration: identiacal with ALC880 */
10989#define alc262_pcm_analog_playback alc880_pcm_analog_playback
10990#define alc262_pcm_analog_capture alc880_pcm_analog_capture
10991#define alc262_pcm_digital_playback alc880_pcm_digital_playback
10992#define alc262_pcm_digital_capture alc880_pcm_digital_capture
10993
10994/*
10995 * BIOS auto configuration
10996 */
10997static int alc262_parse_auto_config(struct hda_codec *codec)
10998{
10999 struct alc_spec *spec = codec->spec;
11000 int err;
11001 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
11002
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011003 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
11004 alc262_ignore);
11005 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011006 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +010011007 if (!spec->autocfg.line_outs) {
Takashi Iwai0852d7a2009-02-11 11:35:15 +010011008 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
Takashi Iwaie64f14f2009-01-20 18:32:55 +010011009 spec->multiout.max_channels = 2;
11010 spec->no_analog = 1;
11011 goto dig_only;
11012 }
Kailang Yangdf694da2005-12-05 19:42:22 +010011013 return 0; /* can't find valid BIOS pin config */
Takashi Iwaie64f14f2009-01-20 18:32:55 +010011014 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011015 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
11016 if (err < 0)
11017 return err;
11018 err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg);
11019 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011020 return err;
11021
11022 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
11023
Takashi Iwaie64f14f2009-01-20 18:32:55 +010011024 dig_only:
Takashi Iwai0852d7a2009-02-11 11:35:15 +010011025 if (spec->autocfg.dig_outs) {
Kailang Yangdf694da2005-12-05 19:42:22 +010011026 spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
Takashi Iwai0852d7a2009-02-11 11:35:15 +010011027 spec->dig_out_type = spec->autocfg.dig_out_type[0];
Takashi Iwaie64f14f2009-01-20 18:32:55 +010011028 }
Kailang Yangdf694da2005-12-05 19:42:22 +010011029 if (spec->autocfg.dig_in_pin)
11030 spec->dig_in_nid = ALC262_DIGIN_NID;
11031
Takashi Iwai603c4012008-07-30 15:01:44 +020011032 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010011033 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010011034
Takashi Iwaid88897e2008-10-31 15:01:37 +010011035 add_verb(spec, alc262_volume_init_verbs);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020011036 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020011037 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010011038
Takashi Iwai776e1842007-08-29 15:07:11 +020011039 err = alc_auto_add_mic_boost(codec);
11040 if (err < 0)
11041 return err;
11042
Takashi Iwai4a79ba342009-04-22 16:31:35 +020011043 alc_ssid_check(codec, 0x15, 0x14, 0x1b);
11044
Kailang Yangdf694da2005-12-05 19:42:22 +010011045 return 1;
11046}
11047
11048#define alc262_auto_init_multi_out alc882_auto_init_multi_out
11049#define alc262_auto_init_hp_out alc882_auto_init_hp_out
11050#define alc262_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaif511b012008-08-15 16:46:42 +020011051#define alc262_auto_init_input_src alc882_auto_init_input_src
Kailang Yangdf694da2005-12-05 19:42:22 +010011052
11053
11054/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +010011055static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010011056{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011057 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010011058 alc262_auto_init_multi_out(codec);
11059 alc262_auto_init_hp_out(codec);
11060 alc262_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020011061 alc262_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011062 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020011063 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010011064}
11065
11066/*
11067 * configuration and preset
11068 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011069static const char *alc262_models[ALC262_MODEL_LAST] = {
11070 [ALC262_BASIC] = "basic",
11071 [ALC262_HIPPO] = "hippo",
11072 [ALC262_HIPPO_1] = "hippo_1",
11073 [ALC262_FUJITSU] = "fujitsu",
11074 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +010011075 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +010011076 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +010011077 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011078 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +020011079 [ALC262_BENQ_T31] = "benq-t31",
11080 [ALC262_SONY_ASSAMD] = "sony-assamd",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020011081 [ALC262_TOSHIBA_S06] = "toshiba-s06",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011082 [ALC262_TOSHIBA_RX1] = "toshiba-rx1",
Tobin Davisf651b502007-10-26 12:40:47 +020011083 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +010011084 [ALC262_LENOVO_3000] = "lenovo-3000",
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011085 [ALC262_NEC] = "nec",
Tony Vroonba340e82009-02-02 19:01:30 +000011086 [ALC262_TYAN] = "tyan",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011087 [ALC262_AUTO] = "auto",
11088};
11089
11090static struct snd_pci_quirk alc262_cfg_tbl[] = {
11091 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011092 SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
Takashi Iwaidea0a502009-02-09 17:14:52 +010011093 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
11094 ALC262_HP_BPC),
11095 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series",
11096 ALC262_HP_BPC),
Takashi Iwai53eff7e2009-02-27 17:49:44 +010011097 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
11098 ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011099 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011100 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011101 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011102 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011103 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011104 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011105 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011106 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011107 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
11108 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
11109 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011110 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
11111 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +010011112 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011113 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011114 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011115 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaibd6afe32009-03-04 11:30:25 +010011116 SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */
Takashi Iwaif872a912009-02-26 00:57:01 +010011117 SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
11118 ALC262_SONY_ASSAMD),
Akio Idehara36ca6e12008-06-09 22:57:40 +090011119 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011120 ALC262_TOSHIBA_RX1),
Kailang Yang80ffe862008-10-15 11:23:27 +020011121 SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011122 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +010011123 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Tony Vroonba340e82009-02-02 19:01:30 +000011124 SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
Takashi Iwaidea0a502009-02-09 17:14:52 +010011125 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1",
11126 ALC262_ULTRA),
Luke Yelavich3e420e72008-12-16 12:37:47 +110011127 SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
Jiang zhe0e31daf2008-03-20 12:12:39 +010011128 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011129 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +020011130 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011131 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +010011132 {}
11133};
11134
11135static struct alc_config_preset alc262_presets[] = {
11136 [ALC262_BASIC] = {
11137 .mixers = { alc262_base_mixer },
11138 .init_verbs = { alc262_init_verbs },
11139 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11140 .dac_nids = alc262_dac_nids,
11141 .hp_nid = 0x03,
11142 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11143 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +010011144 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +010011145 },
Kailang Yangccc656c2006-10-17 12:32:26 +020011146 [ALC262_HIPPO] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011147 .mixers = { alc262_hippo_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +020011148 .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs},
11149 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11150 .dac_nids = alc262_dac_nids,
11151 .hp_nid = 0x03,
11152 .dig_out_nid = ALC262_DIGOUT_NID,
11153 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11154 .channel_mode = alc262_modes,
11155 .input_mux = &alc262_capture_source,
11156 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai42171c12009-05-08 14:11:43 +020011157 .init_hook = alc262_hippo_init_hook,
Kailang Yangccc656c2006-10-17 12:32:26 +020011158 },
11159 [ALC262_HIPPO_1] = {
11160 .mixers = { alc262_hippo1_mixer },
11161 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
11162 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11163 .dac_nids = alc262_dac_nids,
11164 .hp_nid = 0x02,
11165 .dig_out_nid = ALC262_DIGOUT_NID,
11166 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11167 .channel_mode = alc262_modes,
11168 .input_mux = &alc262_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020011169 .unsol_event = alc262_hippo_unsol_event,
11170 .init_hook = alc262_hippo1_init_hook,
Kailang Yangccc656c2006-10-17 12:32:26 +020011171 },
Takashi Iwai834be882006-03-01 14:16:17 +010011172 [ALC262_FUJITSU] = {
11173 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011174 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
11175 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +010011176 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11177 .dac_nids = alc262_dac_nids,
11178 .hp_nid = 0x03,
11179 .dig_out_nid = ALC262_DIGOUT_NID,
11180 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11181 .channel_mode = alc262_modes,
11182 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010011183 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011184 .init_hook = alc262_fujitsu_init_hook,
Takashi Iwai834be882006-03-01 14:16:17 +010011185 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011186 [ALC262_HP_BPC] = {
11187 .mixers = { alc262_HP_BPC_mixer },
11188 .init_verbs = { alc262_HP_BPC_init_verbs },
11189 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11190 .dac_nids = alc262_dac_nids,
11191 .hp_nid = 0x03,
11192 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11193 .channel_mode = alc262_modes,
11194 .input_mux = &alc262_HP_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010011195 .unsol_event = alc262_hp_bpc_unsol_event,
11196 .init_hook = alc262_hp_bpc_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011197 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010011198 [ALC262_HP_BPC_D7000_WF] = {
11199 .mixers = { alc262_HP_BPC_WildWest_mixer },
11200 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
11201 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11202 .dac_nids = alc262_dac_nids,
11203 .hp_nid = 0x03,
11204 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11205 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020011206 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010011207 .unsol_event = alc262_hp_wildwest_unsol_event,
11208 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011209 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010011210 [ALC262_HP_BPC_D7000_WL] = {
11211 .mixers = { alc262_HP_BPC_WildWest_mixer,
11212 alc262_HP_BPC_WildWest_option_mixer },
11213 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
11214 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11215 .dac_nids = alc262_dac_nids,
11216 .hp_nid = 0x03,
11217 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11218 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020011219 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010011220 .unsol_event = alc262_hp_wildwest_unsol_event,
11221 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011222 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011223 [ALC262_HP_TC_T5735] = {
11224 .mixers = { alc262_hp_t5735_mixer },
11225 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
11226 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11227 .dac_nids = alc262_dac_nids,
11228 .hp_nid = 0x03,
11229 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11230 .channel_mode = alc262_modes,
11231 .input_mux = &alc262_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011232 .unsol_event = alc_automute_amp_unsol_event,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011233 .init_hook = alc262_hp_t5735_init_hook,
Kailang Yang8c427222008-01-10 13:03:59 +010011234 },
11235 [ALC262_HP_RP5700] = {
11236 .mixers = { alc262_hp_rp5700_mixer },
11237 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
11238 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11239 .dac_nids = alc262_dac_nids,
11240 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11241 .channel_mode = alc262_modes,
11242 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011243 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +020011244 [ALC262_BENQ_ED8] = {
11245 .mixers = { alc262_base_mixer },
11246 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
11247 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11248 .dac_nids = alc262_dac_nids,
11249 .hp_nid = 0x03,
11250 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11251 .channel_mode = alc262_modes,
11252 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011253 },
Kailang Yang272a5272007-05-14 11:00:38 +020011254 [ALC262_SONY_ASSAMD] = {
11255 .mixers = { alc262_sony_mixer },
11256 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
11257 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11258 .dac_nids = alc262_dac_nids,
11259 .hp_nid = 0x02,
11260 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11261 .channel_mode = alc262_modes,
11262 .input_mux = &alc262_capture_source,
11263 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai42171c12009-05-08 14:11:43 +020011264 .init_hook = alc262_hippo_init_hook,
Kailang Yang83c34212007-07-05 11:43:05 +020011265 },
11266 [ALC262_BENQ_T31] = {
11267 .mixers = { alc262_benq_t31_mixer },
11268 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, alc262_hippo_unsol_verbs },
11269 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11270 .dac_nids = alc262_dac_nids,
11271 .hp_nid = 0x03,
11272 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11273 .channel_mode = alc262_modes,
11274 .input_mux = &alc262_capture_source,
11275 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai42171c12009-05-08 14:11:43 +020011276 .init_hook = alc262_hippo_init_hook,
Kailang Yangea1fb292008-08-26 12:58:38 +020011277 },
Tobin Davisf651b502007-10-26 12:40:47 +020011278 [ALC262_ULTRA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010011279 .mixers = { alc262_ultra_mixer },
11280 .cap_mixer = alc262_ultra_capture_mixer,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011281 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +020011282 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11283 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +020011284 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11285 .channel_mode = alc262_modes,
11286 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011287 .adc_nids = alc262_adc_nids, /* ADC0 */
11288 .capsrc_nids = alc262_capsrc_nids,
11289 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +020011290 .unsol_event = alc262_ultra_unsol_event,
11291 .init_hook = alc262_ultra_automute,
11292 },
Jiang zhe0e31daf2008-03-20 12:12:39 +010011293 [ALC262_LENOVO_3000] = {
11294 .mixers = { alc262_lenovo_3000_mixer },
11295 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
11296 alc262_lenovo_3000_unsol_verbs },
11297 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11298 .dac_nids = alc262_dac_nids,
11299 .hp_nid = 0x03,
11300 .dig_out_nid = ALC262_DIGOUT_NID,
11301 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11302 .channel_mode = alc262_modes,
11303 .input_mux = &alc262_fujitsu_capture_source,
11304 .unsol_event = alc262_lenovo_3000_unsol_event,
11305 },
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011306 [ALC262_NEC] = {
11307 .mixers = { alc262_nec_mixer },
11308 .init_verbs = { alc262_nec_verbs },
11309 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11310 .dac_nids = alc262_dac_nids,
11311 .hp_nid = 0x03,
11312 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11313 .channel_mode = alc262_modes,
11314 .input_mux = &alc262_capture_source,
11315 },
Kailang Yang4e555fe2008-08-26 13:05:55 +020011316 [ALC262_TOSHIBA_S06] = {
11317 .mixers = { alc262_toshiba_s06_mixer },
11318 .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
11319 alc262_eapd_verbs },
11320 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11321 .capsrc_nids = alc262_dmic_capsrc_nids,
11322 .dac_nids = alc262_dac_nids,
11323 .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
11324 .dig_out_nid = ALC262_DIGOUT_NID,
11325 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11326 .channel_mode = alc262_modes,
11327 .input_mux = &alc262_dmic_capture_source,
11328 .unsol_event = alc262_toshiba_s06_unsol_event,
11329 .init_hook = alc262_toshiba_s06_init_hook,
11330 },
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011331 [ALC262_TOSHIBA_RX1] = {
11332 .mixers = { alc262_toshiba_rx1_mixer },
11333 .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
11334 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11335 .dac_nids = alc262_dac_nids,
11336 .hp_nid = 0x03,
11337 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11338 .channel_mode = alc262_modes,
11339 .input_mux = &alc262_capture_source,
11340 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai42171c12009-05-08 14:11:43 +020011341 .init_hook = alc262_hippo_init_hook,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011342 },
Tony Vroonba340e82009-02-02 19:01:30 +000011343 [ALC262_TYAN] = {
11344 .mixers = { alc262_tyan_mixer },
11345 .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
11346 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11347 .dac_nids = alc262_dac_nids,
11348 .hp_nid = 0x02,
11349 .dig_out_nid = ALC262_DIGOUT_NID,
11350 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11351 .channel_mode = alc262_modes,
11352 .input_mux = &alc262_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011353 .unsol_event = alc_automute_amp_unsol_event,
11354 .init_hook = alc262_tyan_init_hook,
Tony Vroonba340e82009-02-02 19:01:30 +000011355 },
Kailang Yangdf694da2005-12-05 19:42:22 +010011356};
11357
11358static int patch_alc262(struct hda_codec *codec)
11359{
11360 struct alc_spec *spec;
11361 int board_config;
11362 int err;
11363
Robert P. J. Daydc041e02006-12-19 14:44:15 +010011364 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010011365 if (spec == NULL)
11366 return -ENOMEM;
11367
11368 codec->spec = spec;
11369#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011370 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
11371 * under-run
11372 */
Kailang Yangdf694da2005-12-05 19:42:22 +010011373 {
11374 int tmp;
11375 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
11376 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
11377 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
11378 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
11379 }
11380#endif
11381
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020011382 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
11383
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011384 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
11385 alc262_models,
11386 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +010011387
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011388 if (board_config < 0) {
Takashi Iwai6c627f32009-05-18 12:33:36 +020011389 printk(KERN_INFO "hda_codec: Unknown model for %s, "
11390 "trying auto-probe from BIOS...\n", codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010011391 board_config = ALC262_AUTO;
11392 }
11393
11394 if (board_config == ALC262_AUTO) {
11395 /* automatic parse from the BIOS config */
11396 err = alc262_parse_auto_config(codec);
11397 if (err < 0) {
11398 alc_free(codec);
11399 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011400 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011401 printk(KERN_INFO
11402 "hda_codec: Cannot set up configuration "
11403 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010011404 board_config = ALC262_BASIC;
11405 }
11406 }
11407
Takashi Iwai07eba612009-02-19 08:06:35 +010011408 if (!spec->no_analog) {
11409 err = snd_hda_attach_beep_device(codec, 0x1);
11410 if (err < 0) {
11411 alc_free(codec);
11412 return err;
11413 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090011414 }
11415
Kailang Yangdf694da2005-12-05 19:42:22 +010011416 if (board_config != ALC262_AUTO)
11417 setup_preset(spec, &alc262_presets[board_config]);
11418
Kailang Yangdf694da2005-12-05 19:42:22 +010011419 spec->stream_analog_playback = &alc262_pcm_analog_playback;
11420 spec->stream_analog_capture = &alc262_pcm_analog_capture;
Kailang Yangea1fb292008-08-26 12:58:38 +020011421
Kailang Yangdf694da2005-12-05 19:42:22 +010011422 spec->stream_digital_playback = &alc262_pcm_digital_playback;
11423 spec->stream_digital_capture = &alc262_pcm_digital_capture;
11424
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020011425 spec->capture_style = CAPT_MIX;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011426 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +010011427 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +010011428 unsigned int wcap = get_wcaps(codec, 0x07);
11429
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011430 /* get type */
11431 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +010011432 if (wcap != AC_WID_AUD_IN) {
11433 spec->adc_nids = alc262_adc_nids_alt;
11434 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt);
Takashi Iwai88c71a92008-02-14 17:27:17 +010011435 spec->capsrc_nids = alc262_capsrc_nids_alt;
Kailang Yangdf694da2005-12-05 19:42:22 +010011436 } else {
11437 spec->adc_nids = alc262_adc_nids;
11438 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids);
Takashi Iwai88c71a92008-02-14 17:27:17 +010011439 spec->capsrc_nids = alc262_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +010011440 }
11441 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +010011442 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaif9e336f2008-10-31 16:37:07 +010011443 set_capture_mixer(spec);
Takashi Iwai07eba612009-02-19 08:06:35 +010011444 if (!spec->no_analog)
11445 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Kailang Yangdf694da2005-12-05 19:42:22 +010011446
Takashi Iwai2134ea42008-01-10 16:53:55 +010011447 spec->vmaster_nid = 0x0c;
11448
Kailang Yangdf694da2005-12-05 19:42:22 +010011449 codec->patch_ops = alc_patch_ops;
11450 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010011451 spec->init_hook = alc262_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020011452#ifdef CONFIG_SND_HDA_POWER_SAVE
11453 if (!spec->loopback.amplist)
11454 spec->loopback.amplist = alc262_loopbacks;
11455#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010011456 codec->proc_widget_hook = print_realtek_coef;
Kailang Yangea1fb292008-08-26 12:58:38 +020011457
Kailang Yangdf694da2005-12-05 19:42:22 +010011458 return 0;
11459}
11460
Kailang Yangdf694da2005-12-05 19:42:22 +010011461/*
Kailang Yanga361d842007-06-05 12:30:55 +020011462 * ALC268 channel source setting (2 channel)
11463 */
11464#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
11465#define alc268_modes alc260_modes
Kailang Yangea1fb292008-08-26 12:58:38 +020011466
Kailang Yanga361d842007-06-05 12:30:55 +020011467static hda_nid_t alc268_dac_nids[2] = {
11468 /* front, hp */
11469 0x02, 0x03
11470};
11471
11472static hda_nid_t alc268_adc_nids[2] = {
11473 /* ADC0-1 */
11474 0x08, 0x07
11475};
11476
11477static hda_nid_t alc268_adc_nids_alt[1] = {
11478 /* ADC0 */
11479 0x08
11480};
11481
Takashi Iwaie1406342008-02-11 18:32:32 +010011482static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
11483
Kailang Yanga361d842007-06-05 12:30:55 +020011484static struct snd_kcontrol_new alc268_base_mixer[] = {
11485 /* output mixer control */
11486 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
11487 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11488 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
11489 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai33bf17a2007-08-21 11:51:42 +020011490 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11491 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11492 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +020011493 { }
11494};
11495
Takashi Iwai42171c12009-05-08 14:11:43 +020011496static struct snd_kcontrol_new alc268_toshiba_mixer[] = {
11497 /* output mixer control */
11498 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
11499 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
11500 ALC262_HIPPO_MASTER_SWITCH,
11501 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11502 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11503 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
11504 { }
11505};
11506
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011507/* bind Beep switches of both NID 0x0f and 0x10 */
11508static struct hda_bind_ctls alc268_bind_beep_sw = {
11509 .ops = &snd_hda_bind_sw,
11510 .values = {
11511 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
11512 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
11513 0
11514 },
11515};
11516
11517static struct snd_kcontrol_new alc268_beep_mixer[] = {
11518 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
11519 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
11520 { }
11521};
11522
Kailang Yangd1a991a2007-08-15 16:21:59 +020011523static struct hda_verb alc268_eapd_verbs[] = {
11524 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
11525 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
11526 { }
11527};
11528
Takashi Iwaid2738092007-08-16 14:59:45 +020011529/* Toshiba specific */
Takashi Iwaid2738092007-08-16 14:59:45 +020011530static struct hda_verb alc268_toshiba_verbs[] = {
11531 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11532 { } /* end */
11533};
11534
Kailang Yang8ef355d2008-08-26 13:10:22 +020011535static struct hda_input_mux alc268_acer_lc_capture_source = {
11536 .num_items = 2,
11537 .items = {
11538 { "i-Mic", 0x6 },
11539 { "E-Mic", 0x0 },
11540 },
11541};
11542
Takashi Iwaid2738092007-08-16 14:59:45 +020011543/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +020011544/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +020011545static struct hda_bind_ctls alc268_acer_bind_master_vol = {
11546 .ops = &snd_hda_bind_vol,
11547 .values = {
11548 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
11549 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
11550 0
11551 },
11552};
11553
Takashi Iwai889c4392007-08-23 18:56:52 +020011554/* mute/unmute internal speaker according to the hp jack and mute state */
11555static void alc268_acer_automute(struct hda_codec *codec, int force)
11556{
11557 struct alc_spec *spec = codec->spec;
11558 unsigned int mute;
11559
11560 if (force || !spec->sense_updated) {
11561 unsigned int present;
11562 present = snd_hda_codec_read(codec, 0x14, 0,
11563 AC_VERB_GET_PIN_SENSE, 0);
11564 spec->jack_present = (present & 0x80000000) != 0;
11565 spec->sense_updated = 1;
11566 }
11567 if (spec->jack_present)
11568 mute = HDA_AMP_MUTE; /* mute internal speaker */
11569 else /* unmute internal speaker if necessary */
11570 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
11571 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
11572 HDA_AMP_MUTE, mute);
11573}
11574
11575
11576/* bind hp and internal speaker mute (with plug check) */
11577static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
11578 struct snd_ctl_elem_value *ucontrol)
11579{
11580 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11581 long *valp = ucontrol->value.integer.value;
11582 int change;
11583
11584 change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
11585 HDA_AMP_MUTE,
11586 valp[0] ? 0 : HDA_AMP_MUTE);
11587 change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
11588 HDA_AMP_MUTE,
11589 valp[1] ? 0 : HDA_AMP_MUTE);
11590 if (change)
11591 alc268_acer_automute(codec, 0);
11592 return change;
11593}
Takashi Iwaid2738092007-08-16 14:59:45 +020011594
Kailang Yang8ef355d2008-08-26 13:10:22 +020011595static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
11596 /* output mixer control */
11597 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
11598 {
11599 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11600 .name = "Master Playback Switch",
11601 .info = snd_hda_mixer_amp_switch_info,
11602 .get = snd_hda_mixer_amp_switch_get,
11603 .put = alc268_acer_master_sw_put,
11604 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11605 },
11606 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
11607 { }
11608};
11609
Takashi Iwaid2738092007-08-16 14:59:45 +020011610static struct snd_kcontrol_new alc268_acer_mixer[] = {
11611 /* output mixer control */
11612 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
11613 {
11614 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11615 .name = "Master Playback Switch",
11616 .info = snd_hda_mixer_amp_switch_info,
11617 .get = snd_hda_mixer_amp_switch_get,
11618 .put = alc268_acer_master_sw_put,
11619 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11620 },
Takashi Iwai33bf17a2007-08-21 11:51:42 +020011621 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11622 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
11623 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +020011624 { }
11625};
11626
Takashi Iwaic238b4f2008-11-05 14:57:20 +010011627static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
11628 /* output mixer control */
11629 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
11630 {
11631 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11632 .name = "Master Playback Switch",
11633 .info = snd_hda_mixer_amp_switch_info,
11634 .get = snd_hda_mixer_amp_switch_get,
11635 .put = alc268_acer_master_sw_put,
11636 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11637 },
11638 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11639 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
11640 { }
11641};
11642
Kailang Yang8ef355d2008-08-26 13:10:22 +020011643static struct hda_verb alc268_acer_aspire_one_verbs[] = {
11644 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11645 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11646 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11647 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11648 {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
11649 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
11650 { }
11651};
11652
Takashi Iwaid2738092007-08-16 14:59:45 +020011653static struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011654 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
11655 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +020011656 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11657 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011658 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11659 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +020011660 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11661 { }
11662};
11663
11664/* unsolicited event for HP jack sensing */
Takashi Iwai42171c12009-05-08 14:11:43 +020011665#define alc268_toshiba_unsol_event alc262_hippo_unsol_event
11666#define alc268_toshiba_init_hook alc262_hippo_init_hook
Takashi Iwaid2738092007-08-16 14:59:45 +020011667
11668static void alc268_acer_unsol_event(struct hda_codec *codec,
11669 unsigned int res)
11670{
Takashi Iwai889c4392007-08-23 18:56:52 +020011671 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020011672 return;
11673 alc268_acer_automute(codec, 1);
11674}
11675
Takashi Iwai889c4392007-08-23 18:56:52 +020011676static void alc268_acer_init_hook(struct hda_codec *codec)
11677{
11678 alc268_acer_automute(codec, 1);
11679}
11680
Kailang Yang8ef355d2008-08-26 13:10:22 +020011681/* toggle speaker-output according to the hp-jack state */
11682static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
11683{
11684 unsigned int present;
11685 unsigned char bits;
11686
11687 present = snd_hda_codec_read(codec, 0x15, 0,
11688 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11689 bits = present ? AMP_IN_MUTE(0) : 0;
11690 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
11691 AMP_IN_MUTE(0), bits);
11692 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1,
11693 AMP_IN_MUTE(0), bits);
11694}
11695
11696
11697static void alc268_acer_mic_automute(struct hda_codec *codec)
11698{
11699 unsigned int present;
11700
11701 present = snd_hda_codec_read(codec, 0x18, 0,
11702 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11703 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_CONNECT_SEL,
11704 present ? 0x0 : 0x6);
11705}
11706
11707static void alc268_acer_lc_unsol_event(struct hda_codec *codec,
11708 unsigned int res)
11709{
11710 if ((res >> 26) == ALC880_HP_EVENT)
11711 alc268_aspire_one_speaker_automute(codec);
11712 if ((res >> 26) == ALC880_MIC_EVENT)
11713 alc268_acer_mic_automute(codec);
11714}
11715
11716static void alc268_acer_lc_init_hook(struct hda_codec *codec)
11717{
11718 alc268_aspire_one_speaker_automute(codec);
11719 alc268_acer_mic_automute(codec);
11720}
11721
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011722static struct snd_kcontrol_new alc268_dell_mixer[] = {
11723 /* output mixer control */
11724 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11725 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11726 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
11727 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11728 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11729 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
11730 { }
11731};
11732
11733static struct hda_verb alc268_dell_verbs[] = {
11734 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11735 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11736 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11737 { }
11738};
11739
11740/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011741static void alc268_dell_init_hook(struct hda_codec *codec)
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011742{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011743 struct alc_spec *spec = codec->spec;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011744
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011745 spec->autocfg.hp_pins[0] = 0x15;
11746 spec->autocfg.speaker_pins[0] = 0x14;
11747 alc_automute_pin(codec);
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011748}
11749
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011750static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
11751 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
11752 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11753 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
11754 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11755 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11756 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
11757 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
11758 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
11759 { }
11760};
11761
11762static struct hda_verb alc267_quanta_il1_verbs[] = {
11763 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11764 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
11765 { }
11766};
11767
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011768static void alc267_quanta_il1_mic_automute(struct hda_codec *codec)
11769{
11770 unsigned int present;
11771
11772 present = snd_hda_codec_read(codec, 0x18, 0,
11773 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11774 snd_hda_codec_write(codec, 0x23, 0,
11775 AC_VERB_SET_CONNECT_SEL,
11776 present ? 0x00 : 0x01);
11777}
11778
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011779static void alc267_quanta_il1_init_hook(struct hda_codec *codec)
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011780{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011781 struct alc_spec *spec = codec->spec;
11782
11783 spec->autocfg.hp_pins[0] = 0x15;
11784 spec->autocfg.speaker_pins[0] = 0x14;
11785 alc_automute_pin(codec);
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011786 alc267_quanta_il1_mic_automute(codec);
11787}
11788
11789static void alc267_quanta_il1_unsol_event(struct hda_codec *codec,
11790 unsigned int res)
11791{
11792 switch (res >> 26) {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011793 case ALC880_MIC_EVENT:
11794 alc267_quanta_il1_mic_automute(codec);
11795 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011796 default:
11797 alc_sku_unsol_event(codec, res);
11798 break;
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011799 }
11800}
11801
Kailang Yanga361d842007-06-05 12:30:55 +020011802/*
11803 * generic initialization of ADC, input mixers and output mixers
11804 */
11805static struct hda_verb alc268_base_init_verbs[] = {
11806 /* Unmute DAC0-1 and set vol = 0 */
11807 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020011808 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020011809
11810 /*
11811 * Set up output mixers (0x0c - 0x0e)
11812 */
11813 /* set vol=0 to output mixers */
11814 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020011815 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
11816
11817 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11818 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11819
11820 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11821 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11822 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11823 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11824 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11825 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11826 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11827 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11828
11829 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11830 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11831 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11832 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020011833 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011834
11835 /* set PCBEEP vol = 0, mute connections */
11836 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11837 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11838 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020011839
Jiang Zhea9b3aa82007-12-20 13:13:13 +010011840 /* Unmute Selector 23h,24h and set the default input to mic-in */
Kailang Yangea1fb292008-08-26 12:58:38 +020011841
Jiang Zhea9b3aa82007-12-20 13:13:13 +010011842 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
11843 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11844 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
11845 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020011846
Kailang Yanga361d842007-06-05 12:30:55 +020011847 { }
11848};
11849
11850/*
11851 * generic initialization of ADC, input mixers and output mixers
11852 */
11853static struct hda_verb alc268_volume_init_verbs[] = {
11854 /* set output DAC */
Takashi Iwai4cfb91c2009-01-23 12:53:09 +010011855 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11856 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020011857
11858 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11859 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11860 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11861 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11862 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11863
Kailang Yanga361d842007-06-05 12:30:55 +020011864 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020011865 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11866 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11867
11868 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020011869 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020011870
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011871 /* set PCBEEP vol = 0, mute connections */
11872 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11873 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11874 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020011875
11876 { }
11877};
11878
Kailang Yanga361d842007-06-05 12:30:55 +020011879static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
11880 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11881 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
11882 {
11883 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11884 /* The multiple "Capture Source" controls confuse alsamixer
11885 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +020011886 */
11887 /* .name = "Capture Source", */
11888 .name = "Input Source",
11889 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011890 .info = alc_mux_enum_info,
11891 .get = alc_mux_enum_get,
11892 .put = alc_mux_enum_put,
Kailang Yanga361d842007-06-05 12:30:55 +020011893 },
11894 { } /* end */
11895};
11896
11897static struct snd_kcontrol_new alc268_capture_mixer[] = {
11898 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11899 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
11900 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
11901 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
11902 {
11903 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11904 /* The multiple "Capture Source" controls confuse alsamixer
11905 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +020011906 */
11907 /* .name = "Capture Source", */
11908 .name = "Input Source",
11909 .count = 2,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011910 .info = alc_mux_enum_info,
11911 .get = alc_mux_enum_get,
11912 .put = alc_mux_enum_put,
Kailang Yanga361d842007-06-05 12:30:55 +020011913 },
11914 { } /* end */
11915};
11916
11917static struct hda_input_mux alc268_capture_source = {
11918 .num_items = 4,
11919 .items = {
11920 { "Mic", 0x0 },
11921 { "Front Mic", 0x1 },
11922 { "Line", 0x2 },
11923 { "CD", 0x3 },
11924 },
11925};
11926
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011927static struct hda_input_mux alc268_acer_capture_source = {
11928 .num_items = 3,
11929 .items = {
11930 { "Mic", 0x0 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010011931 { "Internal Mic", 0x1 },
11932 { "Line", 0x2 },
11933 },
11934};
11935
11936static struct hda_input_mux alc268_acer_dmic_capture_source = {
11937 .num_items = 3,
11938 .items = {
11939 { "Mic", 0x0 },
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011940 { "Internal Mic", 0x6 },
11941 { "Line", 0x2 },
11942 },
11943};
11944
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011945#ifdef CONFIG_SND_DEBUG
11946static struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011947 /* Volume widgets */
11948 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11949 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
11950 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
11951 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
11952 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
11953 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
11954 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
11955 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
11956 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
11957 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
11958 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
11959 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
11960 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010011961 /* The below appears problematic on some hardwares */
11962 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011963 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11964 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
11965 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
11966 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
11967
11968 /* Modes for retasking pin widgets */
11969 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
11970 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
11971 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
11972 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
11973
11974 /* Controls for GPIO pins, assuming they are configured as outputs */
11975 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
11976 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
11977 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
11978 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
11979
11980 /* Switches to allow the digital SPDIF output pin to be enabled.
11981 * The ALC268 does not have an SPDIF input.
11982 */
11983 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
11984
11985 /* A switch allowing EAPD to be enabled. Some laptops seem to use
11986 * this output to turn on an external amplifier.
11987 */
11988 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
11989 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
11990
11991 { } /* end */
11992};
11993#endif
11994
Kailang Yanga361d842007-06-05 12:30:55 +020011995/* create input playback/capture controls for the given pin */
11996static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
11997 const char *ctlname, int idx)
11998{
11999 char name[32];
12000 int err;
12001
12002 sprintf(name, "%s Playback Volume", ctlname);
12003 if (nid == 0x14) {
12004 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
12005 HDA_COMPOSE_AMP_VAL(0x02, 3, idx,
12006 HDA_OUTPUT));
12007 if (err < 0)
12008 return err;
12009 } else if (nid == 0x15) {
12010 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
12011 HDA_COMPOSE_AMP_VAL(0x03, 3, idx,
12012 HDA_OUTPUT));
12013 if (err < 0)
12014 return err;
12015 } else
12016 return -1;
12017 sprintf(name, "%s Playback Switch", ctlname);
12018 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
12019 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
12020 if (err < 0)
12021 return err;
12022 return 0;
12023}
12024
12025/* add playback controls from the parsed DAC table */
12026static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
12027 const struct auto_pin_cfg *cfg)
12028{
12029 hda_nid_t nid;
12030 int err;
12031
12032 spec->multiout.num_dacs = 2; /* only use one dac */
12033 spec->multiout.dac_nids = spec->private_dac_nids;
12034 spec->multiout.dac_nids[0] = 2;
12035 spec->multiout.dac_nids[1] = 3;
12036
12037 nid = cfg->line_out_pins[0];
12038 if (nid)
Kailang Yangea1fb292008-08-26 12:58:38 +020012039 alc268_new_analog_output(spec, nid, "Front", 0);
Kailang Yanga361d842007-06-05 12:30:55 +020012040
12041 nid = cfg->speaker_pins[0];
12042 if (nid == 0x1d) {
12043 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12044 "Speaker Playback Volume",
12045 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
12046 if (err < 0)
12047 return err;
12048 }
12049 nid = cfg->hp_pins[0];
12050 if (nid)
12051 alc268_new_analog_output(spec, nid, "Headphone", 0);
12052
12053 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
12054 if (nid == 0x16) {
12055 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12056 "Mono Playback Switch",
12057 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_INPUT));
12058 if (err < 0)
12059 return err;
12060 }
Kailang Yangea1fb292008-08-26 12:58:38 +020012061 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020012062}
12063
12064/* create playback/capture controls for input pins */
12065static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec,
12066 const struct auto_pin_cfg *cfg)
12067{
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020012068 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yanga361d842007-06-05 12:30:55 +020012069 int i, idx1;
12070
12071 for (i = 0; i < AUTO_PIN_LAST; i++) {
12072 switch(cfg->input_pins[i]) {
12073 case 0x18:
12074 idx1 = 0; /* Mic 1 */
12075 break;
12076 case 0x19:
12077 idx1 = 1; /* Mic 2 */
12078 break;
12079 case 0x1a:
12080 idx1 = 2; /* Line In */
12081 break;
Kailang Yangea1fb292008-08-26 12:58:38 +020012082 case 0x1c:
Kailang Yanga361d842007-06-05 12:30:55 +020012083 idx1 = 3; /* CD */
12084 break;
Takashi Iwai7194cae2008-03-06 16:58:17 +010012085 case 0x12:
12086 case 0x13:
12087 idx1 = 6; /* digital mics */
12088 break;
Kailang Yanga361d842007-06-05 12:30:55 +020012089 default:
12090 continue;
12091 }
12092 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
12093 imux->items[imux->num_items].index = idx1;
Kailang Yangea1fb292008-08-26 12:58:38 +020012094 imux->num_items++;
Kailang Yanga361d842007-06-05 12:30:55 +020012095 }
12096 return 0;
12097}
12098
12099static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
12100{
12101 struct alc_spec *spec = codec->spec;
12102 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
12103 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
12104 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
12105 unsigned int dac_vol1, dac_vol2;
12106
12107 if (speaker_nid) {
12108 snd_hda_codec_write(codec, speaker_nid, 0,
12109 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
12110 snd_hda_codec_write(codec, 0x0f, 0,
12111 AC_VERB_SET_AMP_GAIN_MUTE,
12112 AMP_IN_UNMUTE(1));
12113 snd_hda_codec_write(codec, 0x10, 0,
12114 AC_VERB_SET_AMP_GAIN_MUTE,
12115 AMP_IN_UNMUTE(1));
12116 } else {
12117 snd_hda_codec_write(codec, 0x0f, 0,
12118 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
12119 snd_hda_codec_write(codec, 0x10, 0,
12120 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
12121 }
12122
12123 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020012124 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020012125 dac_vol2 = AMP_OUT_ZERO;
12126 else if (line_nid == 0x15)
12127 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020012128 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020012129 dac_vol2 = AMP_OUT_ZERO;
12130 else if (hp_nid == 0x15)
12131 dac_vol1 = AMP_OUT_ZERO;
12132 if (line_nid != 0x16 || hp_nid != 0x16 ||
12133 spec->autocfg.line_out_pins[1] != 0x16 ||
12134 spec->autocfg.line_out_pins[2] != 0x16)
12135 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
12136
12137 snd_hda_codec_write(codec, 0x02, 0,
12138 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
12139 snd_hda_codec_write(codec, 0x03, 0,
12140 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
12141}
12142
12143/* pcm configuration: identiacal with ALC880 */
12144#define alc268_pcm_analog_playback alc880_pcm_analog_playback
12145#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010012146#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020012147#define alc268_pcm_digital_playback alc880_pcm_digital_playback
12148
12149/*
12150 * BIOS auto configuration
12151 */
12152static int alc268_parse_auto_config(struct hda_codec *codec)
12153{
12154 struct alc_spec *spec = codec->spec;
12155 int err;
12156 static hda_nid_t alc268_ignore[] = { 0 };
12157
12158 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12159 alc268_ignore);
12160 if (err < 0)
12161 return err;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012162 if (!spec->autocfg.line_outs) {
12163 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
12164 spec->multiout.max_channels = 2;
12165 spec->no_analog = 1;
12166 goto dig_only;
12167 }
Kailang Yanga361d842007-06-05 12:30:55 +020012168 return 0; /* can't find valid BIOS pin config */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012169 }
Kailang Yanga361d842007-06-05 12:30:55 +020012170 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
12171 if (err < 0)
12172 return err;
12173 err = alc268_auto_create_analog_input_ctls(spec, &spec->autocfg);
12174 if (err < 0)
12175 return err;
12176
12177 spec->multiout.max_channels = 2;
12178
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012179 dig_only:
Kailang Yanga361d842007-06-05 12:30:55 +020012180 /* digital only support output */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012181 if (spec->autocfg.dig_outs) {
Kailang Yanga361d842007-06-05 12:30:55 +020012182 spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012183 spec->dig_out_type = spec->autocfg.dig_out_type[0];
12184 }
Takashi Iwai603c4012008-07-30 15:01:44 +020012185 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012186 add_mixer(spec, spec->kctls.list);
Kailang Yanga361d842007-06-05 12:30:55 +020012187
Takashi Iwai892981f2009-03-02 08:04:35 +010012188 if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012189 add_mixer(spec, alc268_beep_mixer);
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012190
Takashi Iwaid88897e2008-10-31 15:01:37 +010012191 add_verb(spec, alc268_volume_init_verbs);
Kailang Yanga361d842007-06-05 12:30:55 +020012192 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020012193 spec->input_mux = &spec->private_imux[0];
Kailang Yanga361d842007-06-05 12:30:55 +020012194
Takashi Iwai776e1842007-08-29 15:07:11 +020012195 err = alc_auto_add_mic_boost(codec);
12196 if (err < 0)
12197 return err;
12198
Kailang Yanga361d842007-06-05 12:30:55 +020012199 return 1;
12200}
12201
12202#define alc268_auto_init_multi_out alc882_auto_init_multi_out
12203#define alc268_auto_init_hp_out alc882_auto_init_hp_out
12204#define alc268_auto_init_analog_input alc882_auto_init_analog_input
12205
12206/* init callback for auto-configuration model -- overriding the default init */
12207static void alc268_auto_init(struct hda_codec *codec)
12208{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012209 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020012210 alc268_auto_init_multi_out(codec);
12211 alc268_auto_init_hp_out(codec);
12212 alc268_auto_init_mono_speaker_out(codec);
12213 alc268_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012214 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020012215 alc_inithook(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020012216}
12217
12218/*
12219 * configuration and preset
12220 */
12221static const char *alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012222 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020012223 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020012224 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020012225 [ALC268_ACER] = "acer",
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012226 [ALC268_ACER_DMIC] = "acer-dmic",
Kailang Yang8ef355d2008-08-26 13:10:22 +020012227 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012228 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012229 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010012230#ifdef CONFIG_SND_DEBUG
12231 [ALC268_TEST] = "test",
12232#endif
Kailang Yanga361d842007-06-05 12:30:55 +020012233 [ALC268_AUTO] = "auto",
12234};
12235
12236static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020012237 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012238 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010012239 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012240 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010012241 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020012242 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
12243 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012244 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Takashi Iwai57d13922009-01-08 15:52:09 +010012245 SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron Mini9", ALC268_DELL),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020012246 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series",
12247 ALC268_TOSHIBA),
Kailang Yanga361d842007-06-05 12:30:55 +020012248 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020012249 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
12250 SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
12251 ALC268_TOSHIBA),
Tony Vroon378bd6a2008-06-04 12:08:30 +020012252 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020012253 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012254 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020012255 SND_PCI_QUIRK(0x1854, 0x1775, "LG R510", ALC268_DELL),
Kailang Yanga361d842007-06-05 12:30:55 +020012256 {}
12257};
12258
12259static struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012260 [ALC267_QUANTA_IL1] = {
Takashi Iwai22971e32009-02-10 11:56:44 +010012261 .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer },
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012262 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12263 alc267_quanta_il1_verbs },
12264 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12265 .dac_nids = alc268_dac_nids,
12266 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12267 .adc_nids = alc268_adc_nids_alt,
12268 .hp_nid = 0x03,
12269 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12270 .channel_mode = alc268_modes,
12271 .input_mux = &alc268_capture_source,
12272 .unsol_event = alc267_quanta_il1_unsol_event,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012273 .init_hook = alc267_quanta_il1_init_hook,
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012274 },
Kailang Yanga361d842007-06-05 12:30:55 +020012275 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012276 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
12277 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020012278 .init_verbs = { alc268_base_init_verbs },
12279 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12280 .dac_nids = alc268_dac_nids,
12281 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12282 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010012283 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020012284 .hp_nid = 0x03,
12285 .dig_out_nid = ALC268_DIGOUT_NID,
12286 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12287 .channel_mode = alc268_modes,
12288 .input_mux = &alc268_capture_source,
12289 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020012290 [ALC268_TOSHIBA] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020012291 .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012292 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020012293 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12294 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020012295 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12296 .dac_nids = alc268_dac_nids,
12297 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12298 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010012299 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020012300 .hp_nid = 0x03,
12301 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12302 .channel_mode = alc268_modes,
12303 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020012304 .unsol_event = alc268_toshiba_unsol_event,
Takashi Iwai42171c12009-05-08 14:11:43 +020012305 .init_hook = alc268_toshiba_init_hook,
Takashi Iwaid2738092007-08-16 14:59:45 +020012306 },
12307 [ALC268_ACER] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012308 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
12309 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020012310 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12311 alc268_acer_verbs },
12312 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12313 .dac_nids = alc268_dac_nids,
12314 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12315 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010012316 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020012317 .hp_nid = 0x02,
12318 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12319 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012320 .input_mux = &alc268_acer_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020012321 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020012322 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020012323 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012324 [ALC268_ACER_DMIC] = {
12325 .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
12326 alc268_beep_mixer },
12327 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12328 alc268_acer_verbs },
12329 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12330 .dac_nids = alc268_dac_nids,
12331 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12332 .adc_nids = alc268_adc_nids_alt,
12333 .capsrc_nids = alc268_capsrc_nids,
12334 .hp_nid = 0x02,
12335 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12336 .channel_mode = alc268_modes,
12337 .input_mux = &alc268_acer_dmic_capture_source,
12338 .unsol_event = alc268_acer_unsol_event,
12339 .init_hook = alc268_acer_init_hook,
12340 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020012341 [ALC268_ACER_ASPIRE_ONE] = {
12342 .mixers = { alc268_acer_aspire_one_mixer,
Takashi Iwai22971e32009-02-10 11:56:44 +010012343 alc268_beep_mixer,
12344 alc268_capture_alt_mixer },
Kailang Yang8ef355d2008-08-26 13:10:22 +020012345 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12346 alc268_acer_aspire_one_verbs },
12347 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12348 .dac_nids = alc268_dac_nids,
12349 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12350 .adc_nids = alc268_adc_nids_alt,
12351 .capsrc_nids = alc268_capsrc_nids,
12352 .hp_nid = 0x03,
12353 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12354 .channel_mode = alc268_modes,
12355 .input_mux = &alc268_acer_lc_capture_source,
12356 .unsol_event = alc268_acer_lc_unsol_event,
12357 .init_hook = alc268_acer_lc_init_hook,
12358 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012359 [ALC268_DELL] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012360 .mixers = { alc268_dell_mixer, alc268_beep_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012361 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12362 alc268_dell_verbs },
12363 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12364 .dac_nids = alc268_dac_nids,
12365 .hp_nid = 0x02,
12366 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12367 .channel_mode = alc268_modes,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012368 .unsol_event = alc_sku_unsol_event,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012369 .init_hook = alc268_dell_init_hook,
12370 .input_mux = &alc268_capture_source,
12371 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012372 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012373 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
12374 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012375 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12376 alc268_toshiba_verbs },
12377 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12378 .dac_nids = alc268_dac_nids,
12379 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12380 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010012381 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012382 .hp_nid = 0x03,
12383 .dig_out_nid = ALC268_DIGOUT_NID,
12384 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12385 .channel_mode = alc268_modes,
12386 .input_mux = &alc268_capture_source,
12387 .unsol_event = alc268_toshiba_unsol_event,
Takashi Iwai42171c12009-05-08 14:11:43 +020012388 .init_hook = alc268_toshiba_init_hook
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012389 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010012390#ifdef CONFIG_SND_DEBUG
12391 [ALC268_TEST] = {
12392 .mixers = { alc268_test_mixer, alc268_capture_mixer },
12393 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12394 alc268_volume_init_verbs },
12395 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12396 .dac_nids = alc268_dac_nids,
12397 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12398 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010012399 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010012400 .hp_nid = 0x03,
12401 .dig_out_nid = ALC268_DIGOUT_NID,
12402 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12403 .channel_mode = alc268_modes,
12404 .input_mux = &alc268_capture_source,
12405 },
12406#endif
Kailang Yanga361d842007-06-05 12:30:55 +020012407};
12408
12409static int patch_alc268(struct hda_codec *codec)
12410{
12411 struct alc_spec *spec;
12412 int board_config;
Takashi Iwai22971e32009-02-10 11:56:44 +010012413 int i, has_beep, err;
Kailang Yanga361d842007-06-05 12:30:55 +020012414
12415 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
12416 if (spec == NULL)
12417 return -ENOMEM;
12418
12419 codec->spec = spec;
12420
12421 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
12422 alc268_models,
12423 alc268_cfg_tbl);
12424
12425 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
Takashi Iwai6c627f32009-05-18 12:33:36 +020012426 printk(KERN_INFO "hda_codec: Unknown model for %s, "
12427 "trying auto-probe from BIOS...\n", codec->chip_name);
Kailang Yanga361d842007-06-05 12:30:55 +020012428 board_config = ALC268_AUTO;
12429 }
12430
12431 if (board_config == ALC268_AUTO) {
12432 /* automatic parse from the BIOS config */
12433 err = alc268_parse_auto_config(codec);
12434 if (err < 0) {
12435 alc_free(codec);
12436 return err;
12437 } else if (!err) {
12438 printk(KERN_INFO
12439 "hda_codec: Cannot set up configuration "
12440 "from BIOS. Using base mode...\n");
12441 board_config = ALC268_3ST;
12442 }
12443 }
12444
12445 if (board_config != ALC268_AUTO)
12446 setup_preset(spec, &alc268_presets[board_config]);
12447
Kailang Yanga361d842007-06-05 12:30:55 +020012448 spec->stream_analog_playback = &alc268_pcm_analog_playback;
12449 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010012450 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020012451
Kailang Yanga361d842007-06-05 12:30:55 +020012452 spec->stream_digital_playback = &alc268_pcm_digital_playback;
12453
Takashi Iwai22971e32009-02-10 11:56:44 +010012454 has_beep = 0;
12455 for (i = 0; i < spec->num_mixers; i++) {
12456 if (spec->mixers[i] == alc268_beep_mixer) {
12457 has_beep = 1;
12458 break;
12459 }
12460 }
12461
12462 if (has_beep) {
12463 err = snd_hda_attach_beep_device(codec, 0x1);
12464 if (err < 0) {
12465 alc_free(codec);
12466 return err;
12467 }
12468 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
12469 /* override the amp caps for beep generator */
12470 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012471 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
12472 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
12473 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
12474 (0 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwai22971e32009-02-10 11:56:44 +010012475 }
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012476
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012477 if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012478 /* check whether NID 0x07 is valid */
12479 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwai85860c02008-02-19 15:00:15 +010012480 int i;
Kailang Yanga361d842007-06-05 12:30:55 +020012481
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012482 /* get type */
12483 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwai67ebcb02008-02-19 15:03:57 +010012484 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012485 spec->adc_nids = alc268_adc_nids_alt;
12486 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
Takashi Iwaid88897e2008-10-31 15:01:37 +010012487 add_mixer(spec, alc268_capture_alt_mixer);
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012488 } else {
12489 spec->adc_nids = alc268_adc_nids;
12490 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
Takashi Iwaid88897e2008-10-31 15:01:37 +010012491 add_mixer(spec, alc268_capture_mixer);
Kailang Yanga361d842007-06-05 12:30:55 +020012492 }
Takashi Iwaie1406342008-02-11 18:32:32 +010012493 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai85860c02008-02-19 15:00:15 +010012494 /* set default input source */
12495 for (i = 0; i < spec->num_adc_nids; i++)
12496 snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
12497 0, AC_VERB_SET_CONNECT_SEL,
12498 spec->input_mux->items[0].index);
Kailang Yanga361d842007-06-05 12:30:55 +020012499 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010012500
12501 spec->vmaster_nid = 0x02;
12502
Kailang Yanga361d842007-06-05 12:30:55 +020012503 codec->patch_ops = alc_patch_ops;
12504 if (board_config == ALC268_AUTO)
12505 spec->init_hook = alc268_auto_init;
Kailang Yangea1fb292008-08-26 12:58:38 +020012506
Takashi Iwaidaead532008-11-28 12:55:36 +010012507 codec->proc_widget_hook = print_realtek_coef;
12508
Kailang Yanga361d842007-06-05 12:30:55 +020012509 return 0;
12510}
12511
12512/*
Kailang Yangf6a92242007-12-13 16:52:54 +010012513 * ALC269 channel source setting (2 channel)
12514 */
12515#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
12516
12517#define alc269_dac_nids alc260_dac_nids
12518
12519static hda_nid_t alc269_adc_nids[1] = {
12520 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020012521 0x08,
12522};
12523
Takashi Iwaie01bf502008-08-21 16:25:07 +020012524static hda_nid_t alc269_capsrc_nids[1] = {
12525 0x23,
12526};
12527
12528/* NOTE: ADC2 (0x07) is connected from a recording *MIXER* (0x24),
12529 * not a mux!
12530 */
12531
Kailang Yangf53281e2008-07-18 12:36:43 +020012532static struct hda_input_mux alc269_eeepc_dmic_capture_source = {
12533 .num_items = 2,
12534 .items = {
12535 { "i-Mic", 0x5 },
12536 { "e-Mic", 0x0 },
12537 },
12538};
12539
12540static struct hda_input_mux alc269_eeepc_amic_capture_source = {
12541 .num_items = 2,
12542 .items = {
12543 { "i-Mic", 0x1 },
12544 { "e-Mic", 0x0 },
12545 },
Kailang Yangf6a92242007-12-13 16:52:54 +010012546};
12547
12548#define alc269_modes alc260_modes
12549#define alc269_capture_source alc880_lg_lw_capture_source
12550
12551static struct snd_kcontrol_new alc269_base_mixer[] = {
12552 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12553 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12554 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
12555 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
12556 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12557 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12558 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12559 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
12560 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
12561 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12562 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12563 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
12564 { } /* end */
12565};
12566
Kailang Yang60db6b52008-08-26 13:13:00 +020012567static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
12568 /* output mixer control */
12569 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12570 {
12571 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12572 .name = "Master Playback Switch",
12573 .info = snd_hda_mixer_amp_switch_info,
12574 .get = snd_hda_mixer_amp_switch_get,
12575 .put = alc268_acer_master_sw_put,
12576 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12577 },
12578 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12579 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12580 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12581 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
12582 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
12583 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020012584 { }
12585};
12586
Tony Vroon64154832008-11-06 15:08:49 +000012587static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
12588 /* output mixer control */
12589 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12590 {
12591 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12592 .name = "Master Playback Switch",
12593 .info = snd_hda_mixer_amp_switch_info,
12594 .get = snd_hda_mixer_amp_switch_get,
12595 .put = alc268_acer_master_sw_put,
12596 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12597 },
12598 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12599 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12600 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12601 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
12602 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
12603 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
12604 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
12605 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
12606 HDA_CODEC_VOLUME("Dock Mic Boost", 0x1b, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000012607 { }
12608};
12609
Kailang Yangf53281e2008-07-18 12:36:43 +020012610/* bind volumes of both NID 0x0c and 0x0d */
12611static struct hda_bind_ctls alc269_epc_bind_vol = {
12612 .ops = &snd_hda_bind_vol,
12613 .values = {
12614 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
12615 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
12616 0
12617 },
12618};
12619
12620static struct snd_kcontrol_new alc269_eeepc_mixer[] = {
12621 HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12622 HDA_BIND_VOL("LineOut Playback Volume", &alc269_epc_bind_vol),
12623 HDA_CODEC_MUTE("LineOut Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12624 { } /* end */
12625};
12626
Kailang Yangf6a92242007-12-13 16:52:54 +010012627/* capture mixer elements */
Kailang Yangf53281e2008-07-18 12:36:43 +020012628static struct snd_kcontrol_new alc269_epc_capture_mixer[] = {
12629 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
12630 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Takashi Iwai26f5df22008-11-03 17:39:46 +010012631 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12632 { } /* end */
12633};
12634
12635/* FSC amilo */
12636static struct snd_kcontrol_new alc269_fujitsu_mixer[] = {
12637 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12638 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12639 HDA_BIND_VOL("PCM Playback Volume", &alc269_epc_bind_vol),
Kailang Yangf53281e2008-07-18 12:36:43 +020012640 { } /* end */
12641};
12642
Kailang Yang60db6b52008-08-26 13:13:00 +020012643static struct hda_verb alc269_quanta_fl1_verbs[] = {
12644 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12645 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12646 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12647 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12648 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12649 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12650 { }
12651};
12652
Tony Vroon64154832008-11-06 15:08:49 +000012653static struct hda_verb alc269_lifebook_verbs[] = {
12654 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12655 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
12656 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12657 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12658 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12659 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12660 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12661 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12662 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12663 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12664 { }
12665};
12666
Kailang Yang60db6b52008-08-26 13:13:00 +020012667/* toggle speaker-output according to the hp-jack state */
12668static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
12669{
12670 unsigned int present;
12671 unsigned char bits;
12672
12673 present = snd_hda_codec_read(codec, 0x15, 0,
12674 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12675 bits = present ? AMP_IN_MUTE(0) : 0;
12676 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
12677 AMP_IN_MUTE(0), bits);
12678 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
12679 AMP_IN_MUTE(0), bits);
12680
12681 snd_hda_codec_write(codec, 0x20, 0,
12682 AC_VERB_SET_COEF_INDEX, 0x0c);
12683 snd_hda_codec_write(codec, 0x20, 0,
12684 AC_VERB_SET_PROC_COEF, 0x680);
12685
12686 snd_hda_codec_write(codec, 0x20, 0,
12687 AC_VERB_SET_COEF_INDEX, 0x0c);
12688 snd_hda_codec_write(codec, 0x20, 0,
12689 AC_VERB_SET_PROC_COEF, 0x480);
12690}
12691
Tony Vroon64154832008-11-06 15:08:49 +000012692/* toggle speaker-output according to the hp-jacks state */
12693static void alc269_lifebook_speaker_automute(struct hda_codec *codec)
12694{
12695 unsigned int present;
12696 unsigned char bits;
12697
12698 /* Check laptop headphone socket */
12699 present = snd_hda_codec_read(codec, 0x15, 0,
12700 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12701
12702 /* Check port replicator headphone socket */
12703 present |= snd_hda_codec_read(codec, 0x1a, 0,
12704 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12705
12706 bits = present ? AMP_IN_MUTE(0) : 0;
12707 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
12708 AMP_IN_MUTE(0), bits);
12709 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
12710 AMP_IN_MUTE(0), bits);
12711
12712 snd_hda_codec_write(codec, 0x20, 0,
12713 AC_VERB_SET_COEF_INDEX, 0x0c);
12714 snd_hda_codec_write(codec, 0x20, 0,
12715 AC_VERB_SET_PROC_COEF, 0x680);
12716
12717 snd_hda_codec_write(codec, 0x20, 0,
12718 AC_VERB_SET_COEF_INDEX, 0x0c);
12719 snd_hda_codec_write(codec, 0x20, 0,
12720 AC_VERB_SET_PROC_COEF, 0x480);
12721}
12722
Kailang Yang60db6b52008-08-26 13:13:00 +020012723static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec)
12724{
12725 unsigned int present;
12726
12727 present = snd_hda_codec_read(codec, 0x18, 0,
12728 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12729 snd_hda_codec_write(codec, 0x23, 0,
12730 AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x1);
12731}
12732
Tony Vroon64154832008-11-06 15:08:49 +000012733static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
12734{
12735 unsigned int present_laptop;
12736 unsigned int present_dock;
12737
12738 present_laptop = snd_hda_codec_read(codec, 0x18, 0,
12739 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12740
12741 present_dock = snd_hda_codec_read(codec, 0x1b, 0,
12742 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12743
12744 /* Laptop mic port overrides dock mic port, design decision */
12745 if (present_dock)
12746 snd_hda_codec_write(codec, 0x23, 0,
12747 AC_VERB_SET_CONNECT_SEL, 0x3);
12748 if (present_laptop)
12749 snd_hda_codec_write(codec, 0x23, 0,
12750 AC_VERB_SET_CONNECT_SEL, 0x0);
12751 if (!present_dock && !present_laptop)
12752 snd_hda_codec_write(codec, 0x23, 0,
12753 AC_VERB_SET_CONNECT_SEL, 0x1);
12754}
12755
Kailang Yang60db6b52008-08-26 13:13:00 +020012756static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
12757 unsigned int res)
12758{
12759 if ((res >> 26) == ALC880_HP_EVENT)
12760 alc269_quanta_fl1_speaker_automute(codec);
12761 if ((res >> 26) == ALC880_MIC_EVENT)
12762 alc269_quanta_fl1_mic_automute(codec);
12763}
12764
Tony Vroon64154832008-11-06 15:08:49 +000012765static void alc269_lifebook_unsol_event(struct hda_codec *codec,
12766 unsigned int res)
12767{
12768 if ((res >> 26) == ALC880_HP_EVENT)
12769 alc269_lifebook_speaker_automute(codec);
12770 if ((res >> 26) == ALC880_MIC_EVENT)
12771 alc269_lifebook_mic_autoswitch(codec);
12772}
12773
Kailang Yang60db6b52008-08-26 13:13:00 +020012774static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
12775{
12776 alc269_quanta_fl1_speaker_automute(codec);
12777 alc269_quanta_fl1_mic_automute(codec);
12778}
12779
Tony Vroon64154832008-11-06 15:08:49 +000012780static void alc269_lifebook_init_hook(struct hda_codec *codec)
12781{
12782 alc269_lifebook_speaker_automute(codec);
12783 alc269_lifebook_mic_autoswitch(codec);
12784}
12785
Kailang Yang60db6b52008-08-26 13:13:00 +020012786static struct hda_verb alc269_eeepc_dmic_init_verbs[] = {
12787 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12788 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
12789 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
12790 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
12791 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12792 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12793 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12794 {}
12795};
12796
12797static struct hda_verb alc269_eeepc_amic_init_verbs[] = {
12798 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12799 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
12800 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
12801 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
12802 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12803 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12804 {}
12805};
12806
12807/* toggle speaker-output according to the hp-jack state */
12808static void alc269_speaker_automute(struct hda_codec *codec)
12809{
12810 unsigned int present;
12811 unsigned char bits;
12812
12813 present = snd_hda_codec_read(codec, 0x15, 0,
12814 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12815 bits = present ? AMP_IN_MUTE(0) : 0;
12816 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
12817 AMP_IN_MUTE(0), bits);
12818 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
12819 AMP_IN_MUTE(0), bits);
12820}
12821
12822static void alc269_eeepc_dmic_automute(struct hda_codec *codec)
12823{
12824 unsigned int present;
12825
12826 present = snd_hda_codec_read(codec, 0x18, 0,
12827 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12828 snd_hda_codec_write(codec, 0x23, 0,
12829 AC_VERB_SET_CONNECT_SEL, (present ? 0 : 5));
12830}
12831
12832static void alc269_eeepc_amic_automute(struct hda_codec *codec)
12833{
12834 unsigned int present;
12835
12836 present = snd_hda_codec_read(codec, 0x18, 0,
12837 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12838 snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE,
12839 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
12840 snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE,
12841 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
12842}
12843
12844/* unsolicited event for HP jack sensing */
12845static void alc269_eeepc_dmic_unsol_event(struct hda_codec *codec,
12846 unsigned int res)
12847{
12848 if ((res >> 26) == ALC880_HP_EVENT)
12849 alc269_speaker_automute(codec);
12850
12851 if ((res >> 26) == ALC880_MIC_EVENT)
12852 alc269_eeepc_dmic_automute(codec);
12853}
12854
12855static void alc269_eeepc_dmic_inithook(struct hda_codec *codec)
12856{
12857 alc269_speaker_automute(codec);
12858 alc269_eeepc_dmic_automute(codec);
12859}
12860
12861/* unsolicited event for HP jack sensing */
12862static void alc269_eeepc_amic_unsol_event(struct hda_codec *codec,
12863 unsigned int res)
12864{
12865 if ((res >> 26) == ALC880_HP_EVENT)
12866 alc269_speaker_automute(codec);
12867
12868 if ((res >> 26) == ALC880_MIC_EVENT)
12869 alc269_eeepc_amic_automute(codec);
12870}
12871
12872static void alc269_eeepc_amic_inithook(struct hda_codec *codec)
12873{
12874 alc269_speaker_automute(codec);
12875 alc269_eeepc_amic_automute(codec);
12876}
12877
Kailang Yangf6a92242007-12-13 16:52:54 +010012878/*
12879 * generic initialization of ADC, input mixers and output mixers
12880 */
12881static struct hda_verb alc269_init_verbs[] = {
12882 /*
12883 * Unmute ADC0 and set the default input to mic-in
12884 */
Kailang Yang60db6b52008-08-26 13:13:00 +020012885 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010012886
12887 /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the
12888 * analog-loopback mixer widget
12889 * Note: PASD motherboards uses the Line In 2 as the input for
12890 * front panel mic (mic 2)
12891 */
12892 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
12893 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12894 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12895 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12896 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12897 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12898
12899 /*
12900 * Set up output mixers (0x0c - 0x0e)
12901 */
12902 /* set vol=0 to output mixers */
12903 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12904 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12905
12906 /* set up input amps for analog loopback */
12907 /* Amp Indices: DAC = 0, mixer = 1 */
12908 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12909 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12910 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12911 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12912 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12913 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12914
12915 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12916 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12917 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12918 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12919 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12920 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12921 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12922
12923 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12924 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12925 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12926 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12927 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12928 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12929 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12930
12931 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
12932 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12933
12934 /* FIXME: use matrix-type input source selection */
12935 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
12936 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang60db6b52008-08-26 13:13:00 +020012937 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12938 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangf6a92242007-12-13 16:52:54 +010012939 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12940 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12941
12942 /* set EAPD */
12943 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
12944 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
12945 { }
12946};
12947
12948/* add playback controls from the parsed DAC table */
12949static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec,
12950 const struct auto_pin_cfg *cfg)
12951{
12952 hda_nid_t nid;
12953 int err;
12954
12955 spec->multiout.num_dacs = 1; /* only use one dac */
12956 spec->multiout.dac_nids = spec->private_dac_nids;
12957 spec->multiout.dac_nids[0] = 2;
12958
12959 nid = cfg->line_out_pins[0];
12960 if (nid) {
12961 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12962 "Front Playback Volume",
12963 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT));
12964 if (err < 0)
12965 return err;
12966 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12967 "Front Playback Switch",
12968 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
12969 if (err < 0)
12970 return err;
12971 }
12972
12973 nid = cfg->speaker_pins[0];
12974 if (nid) {
12975 if (!cfg->line_out_pins[0]) {
12976 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12977 "Speaker Playback Volume",
12978 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
12979 HDA_OUTPUT));
12980 if (err < 0)
12981 return err;
12982 }
12983 if (nid == 0x16) {
12984 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12985 "Speaker Playback Switch",
12986 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
12987 HDA_OUTPUT));
12988 if (err < 0)
12989 return err;
12990 } else {
12991 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12992 "Speaker Playback Switch",
12993 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
12994 HDA_OUTPUT));
12995 if (err < 0)
12996 return err;
12997 }
12998 }
12999 nid = cfg->hp_pins[0];
13000 if (nid) {
13001 /* spec->multiout.hp_nid = 2; */
13002 if (!cfg->line_out_pins[0] && !cfg->speaker_pins[0]) {
13003 err = add_control(spec, ALC_CTL_WIDGET_VOL,
13004 "Headphone Playback Volume",
13005 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
13006 HDA_OUTPUT));
13007 if (err < 0)
13008 return err;
13009 }
13010 if (nid == 0x16) {
13011 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
13012 "Headphone Playback Switch",
13013 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
13014 HDA_OUTPUT));
13015 if (err < 0)
13016 return err;
13017 } else {
13018 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
13019 "Headphone Playback Switch",
13020 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
13021 HDA_OUTPUT));
13022 if (err < 0)
13023 return err;
13024 }
13025 }
13026 return 0;
13027}
13028
Takashi Iwaiee956e02008-10-31 17:16:31 +010013029static int alc269_auto_create_analog_input_ctls(struct alc_spec *spec,
13030 const struct auto_pin_cfg *cfg)
13031{
13032 int err;
13033
13034 err = alc880_auto_create_analog_input_ctls(spec, cfg);
13035 if (err < 0)
13036 return err;
13037 /* digital-mic input pin is excluded in alc880_auto_create..()
13038 * because it's under 0x18
13039 */
13040 if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
13041 cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020013042 struct hda_input_mux *imux = &spec->private_imux[0];
Takashi Iwaiee956e02008-10-31 17:16:31 +010013043 imux->items[imux->num_items].label = "Int Mic";
13044 imux->items[imux->num_items].index = 0x05;
13045 imux->num_items++;
13046 }
13047 return 0;
13048}
Kailang Yangf6a92242007-12-13 16:52:54 +010013049
13050#ifdef CONFIG_SND_HDA_POWER_SAVE
13051#define alc269_loopbacks alc880_loopbacks
13052#endif
13053
13054/* pcm configuration: identiacal with ALC880 */
13055#define alc269_pcm_analog_playback alc880_pcm_analog_playback
13056#define alc269_pcm_analog_capture alc880_pcm_analog_capture
13057#define alc269_pcm_digital_playback alc880_pcm_digital_playback
13058#define alc269_pcm_digital_capture alc880_pcm_digital_capture
13059
Takashi Iwaif03d3112009-03-05 14:18:16 +010013060static struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
13061 .substreams = 1,
13062 .channels_min = 2,
13063 .channels_max = 8,
13064 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
13065 /* NID is set in alc_build_pcms */
13066 .ops = {
13067 .open = alc880_playback_pcm_open,
13068 .prepare = alc880_playback_pcm_prepare,
13069 .cleanup = alc880_playback_pcm_cleanup
13070 },
13071};
13072
13073static struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
13074 .substreams = 1,
13075 .channels_min = 2,
13076 .channels_max = 2,
13077 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
13078 /* NID is set in alc_build_pcms */
13079};
13080
Kailang Yangf6a92242007-12-13 16:52:54 +010013081/*
13082 * BIOS auto configuration
13083 */
13084static int alc269_parse_auto_config(struct hda_codec *codec)
13085{
13086 struct alc_spec *spec = codec->spec;
Takashi Iwaicfb9fb52009-02-06 17:34:03 +010013087 int err;
Kailang Yangf6a92242007-12-13 16:52:54 +010013088 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
13089
13090 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13091 alc269_ignore);
13092 if (err < 0)
13093 return err;
13094
13095 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
13096 if (err < 0)
13097 return err;
13098 err = alc269_auto_create_analog_input_ctls(spec, &spec->autocfg);
13099 if (err < 0)
13100 return err;
13101
13102 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
13103
Takashi Iwai0852d7a2009-02-11 11:35:15 +010013104 if (spec->autocfg.dig_outs)
Kailang Yangf6a92242007-12-13 16:52:54 +010013105 spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
13106
Takashi Iwai603c4012008-07-30 15:01:44 +020013107 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013108 add_mixer(spec, spec->kctls.list);
Kailang Yangf6a92242007-12-13 16:52:54 +010013109
Takashi Iwaid88897e2008-10-31 15:01:37 +010013110 add_verb(spec, alc269_init_verbs);
Kailang Yangf6a92242007-12-13 16:52:54 +010013111 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020013112 spec->input_mux = &spec->private_imux[0];
Takashi Iwaie01bf502008-08-21 16:25:07 +020013113 /* set default input source */
13114 snd_hda_codec_write_cache(codec, alc269_capsrc_nids[0],
13115 0, AC_VERB_SET_CONNECT_SEL,
13116 spec->input_mux->items[0].index);
Kailang Yangf6a92242007-12-13 16:52:54 +010013117
13118 err = alc_auto_add_mic_boost(codec);
13119 if (err < 0)
13120 return err;
13121
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013122 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaif9e336f2008-10-31 16:37:07 +010013123 set_capture_mixer(spec);
Kailang Yangf53281e2008-07-18 12:36:43 +020013124
Kailang Yangf6a92242007-12-13 16:52:54 +010013125 return 1;
13126}
13127
13128#define alc269_auto_init_multi_out alc882_auto_init_multi_out
13129#define alc269_auto_init_hp_out alc882_auto_init_hp_out
13130#define alc269_auto_init_analog_input alc882_auto_init_analog_input
13131
13132
13133/* init callback for auto-configuration model -- overriding the default init */
13134static void alc269_auto_init(struct hda_codec *codec)
13135{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013136 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010013137 alc269_auto_init_multi_out(codec);
13138 alc269_auto_init_hp_out(codec);
13139 alc269_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013140 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020013141 alc_inithook(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010013142}
13143
13144/*
13145 * configuration and preset
13146 */
13147static const char *alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020013148 [ALC269_BASIC] = "basic",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020013149 [ALC269_QUANTA_FL1] = "quanta",
13150 [ALC269_ASUS_EEEPC_P703] = "eeepc-p703",
Takashi Iwai26f5df22008-11-03 17:39:46 +010013151 [ALC269_ASUS_EEEPC_P901] = "eeepc-p901",
Tony Vroon64154832008-11-06 15:08:49 +000013152 [ALC269_FUJITSU] = "fujitsu",
13153 [ALC269_LIFEBOOK] = "lifebook"
Kailang Yangf6a92242007-12-13 16:52:54 +010013154};
13155
13156static struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020013157 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangf53281e2008-07-18 12:36:43 +020013158 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
13159 ALC269_ASUS_EEEPC_P703),
Kailang Yang622e84c2009-04-21 07:39:04 +020013160 SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_ASUS_EEEPC_P703),
13161 SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_ASUS_EEEPC_P703),
13162 SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_ASUS_EEEPC_P703),
13163 SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_ASUS_EEEPC_P703),
13164 SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_ASUS_EEEPC_P703),
13165 SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_ASUS_EEEPC_P703),
Kailang Yangf53281e2008-07-18 12:36:43 +020013166 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
13167 ALC269_ASUS_EEEPC_P901),
Kailang Yang60db6b52008-08-26 13:13:00 +020013168 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
13169 ALC269_ASUS_EEEPC_P901),
Kailang Yang622e84c2009-04-21 07:39:04 +020013170 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_ASUS_EEEPC_P901),
Takashi Iwai26f5df22008-11-03 17:39:46 +010013171 SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
Tony Vroon64154832008-11-06 15:08:49 +000013172 SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
Kailang Yangf6a92242007-12-13 16:52:54 +010013173 {}
13174};
13175
13176static struct alc_config_preset alc269_presets[] = {
13177 [ALC269_BASIC] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010013178 .mixers = { alc269_base_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010013179 .init_verbs = { alc269_init_verbs },
13180 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13181 .dac_nids = alc269_dac_nids,
13182 .hp_nid = 0x03,
13183 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13184 .channel_mode = alc269_modes,
13185 .input_mux = &alc269_capture_source,
13186 },
Kailang Yang60db6b52008-08-26 13:13:00 +020013187 [ALC269_QUANTA_FL1] = {
13188 .mixers = { alc269_quanta_fl1_mixer },
13189 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
13190 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13191 .dac_nids = alc269_dac_nids,
13192 .hp_nid = 0x03,
13193 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13194 .channel_mode = alc269_modes,
13195 .input_mux = &alc269_capture_source,
13196 .unsol_event = alc269_quanta_fl1_unsol_event,
13197 .init_hook = alc269_quanta_fl1_init_hook,
13198 },
Kailang Yangf53281e2008-07-18 12:36:43 +020013199 [ALC269_ASUS_EEEPC_P703] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010013200 .mixers = { alc269_eeepc_mixer },
13201 .cap_mixer = alc269_epc_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020013202 .init_verbs = { alc269_init_verbs,
13203 alc269_eeepc_amic_init_verbs },
13204 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13205 .dac_nids = alc269_dac_nids,
13206 .hp_nid = 0x03,
13207 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13208 .channel_mode = alc269_modes,
13209 .input_mux = &alc269_eeepc_amic_capture_source,
13210 .unsol_event = alc269_eeepc_amic_unsol_event,
13211 .init_hook = alc269_eeepc_amic_inithook,
13212 },
13213 [ALC269_ASUS_EEEPC_P901] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010013214 .mixers = { alc269_eeepc_mixer },
13215 .cap_mixer = alc269_epc_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020013216 .init_verbs = { alc269_init_verbs,
13217 alc269_eeepc_dmic_init_verbs },
13218 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13219 .dac_nids = alc269_dac_nids,
13220 .hp_nid = 0x03,
13221 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13222 .channel_mode = alc269_modes,
13223 .input_mux = &alc269_eeepc_dmic_capture_source,
13224 .unsol_event = alc269_eeepc_dmic_unsol_event,
13225 .init_hook = alc269_eeepc_dmic_inithook,
13226 },
Takashi Iwai26f5df22008-11-03 17:39:46 +010013227 [ALC269_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010013228 .mixers = { alc269_fujitsu_mixer },
Takashi Iwai26f5df22008-11-03 17:39:46 +010013229 .cap_mixer = alc269_epc_capture_mixer,
13230 .init_verbs = { alc269_init_verbs,
13231 alc269_eeepc_dmic_init_verbs },
13232 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13233 .dac_nids = alc269_dac_nids,
13234 .hp_nid = 0x03,
13235 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13236 .channel_mode = alc269_modes,
13237 .input_mux = &alc269_eeepc_dmic_capture_source,
13238 .unsol_event = alc269_eeepc_dmic_unsol_event,
13239 .init_hook = alc269_eeepc_dmic_inithook,
13240 },
Tony Vroon64154832008-11-06 15:08:49 +000013241 [ALC269_LIFEBOOK] = {
13242 .mixers = { alc269_lifebook_mixer },
13243 .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
13244 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13245 .dac_nids = alc269_dac_nids,
13246 .hp_nid = 0x03,
13247 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13248 .channel_mode = alc269_modes,
13249 .input_mux = &alc269_capture_source,
13250 .unsol_event = alc269_lifebook_unsol_event,
13251 .init_hook = alc269_lifebook_init_hook,
13252 },
Kailang Yangf6a92242007-12-13 16:52:54 +010013253};
13254
13255static int patch_alc269(struct hda_codec *codec)
13256{
13257 struct alc_spec *spec;
13258 int board_config;
13259 int err;
13260
13261 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
13262 if (spec == NULL)
13263 return -ENOMEM;
13264
13265 codec->spec = spec;
13266
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020013267 alc_fix_pll_init(codec, 0x20, 0x04, 15);
13268
Kailang Yangf6a92242007-12-13 16:52:54 +010013269 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
13270 alc269_models,
13271 alc269_cfg_tbl);
13272
13273 if (board_config < 0) {
Takashi Iwai6c627f32009-05-18 12:33:36 +020013274 printk(KERN_INFO "hda_codec: Unknown model for %s, "
13275 "trying auto-probe from BIOS...\n", codec->chip_name);
Kailang Yangf6a92242007-12-13 16:52:54 +010013276 board_config = ALC269_AUTO;
13277 }
13278
13279 if (board_config == ALC269_AUTO) {
13280 /* automatic parse from the BIOS config */
13281 err = alc269_parse_auto_config(codec);
13282 if (err < 0) {
13283 alc_free(codec);
13284 return err;
13285 } else if (!err) {
13286 printk(KERN_INFO
13287 "hda_codec: Cannot set up configuration "
13288 "from BIOS. Using base mode...\n");
13289 board_config = ALC269_BASIC;
13290 }
13291 }
13292
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090013293 err = snd_hda_attach_beep_device(codec, 0x1);
13294 if (err < 0) {
13295 alc_free(codec);
13296 return err;
13297 }
13298
Kailang Yangf6a92242007-12-13 16:52:54 +010013299 if (board_config != ALC269_AUTO)
13300 setup_preset(spec, &alc269_presets[board_config]);
13301
Takashi Iwaif03d3112009-03-05 14:18:16 +010013302 if (codec->subsystem_id == 0x17aa3bf8) {
13303 /* Due to a hardware problem on Lenovo Ideadpad, we need to
13304 * fix the sample rate of analog I/O to 44.1kHz
13305 */
13306 spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
13307 spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
13308 } else {
13309 spec->stream_analog_playback = &alc269_pcm_analog_playback;
13310 spec->stream_analog_capture = &alc269_pcm_analog_capture;
13311 }
Kailang Yangf6a92242007-12-13 16:52:54 +010013312 spec->stream_digital_playback = &alc269_pcm_digital_playback;
13313 spec->stream_digital_capture = &alc269_pcm_digital_capture;
13314
13315 spec->adc_nids = alc269_adc_nids;
13316 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
Takashi Iwaie01bf502008-08-21 16:25:07 +020013317 spec->capsrc_nids = alc269_capsrc_nids;
Takashi Iwaif9e336f2008-10-31 16:37:07 +010013318 if (!spec->cap_mixer)
13319 set_capture_mixer(spec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010013320 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Kailang Yangf6a92242007-12-13 16:52:54 +010013321
13322 codec->patch_ops = alc_patch_ops;
13323 if (board_config == ALC269_AUTO)
13324 spec->init_hook = alc269_auto_init;
13325#ifdef CONFIG_SND_HDA_POWER_SAVE
13326 if (!spec->loopback.amplist)
13327 spec->loopback.amplist = alc269_loopbacks;
13328#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010013329 codec->proc_widget_hook = print_realtek_coef;
Kailang Yangf6a92242007-12-13 16:52:54 +010013330
13331 return 0;
13332}
13333
13334/*
Kailang Yangdf694da2005-12-05 19:42:22 +010013335 * ALC861 channel source setting (2/6 channel selection for 3-stack)
13336 */
13337
13338/*
13339 * set the path ways for 2 channel output
13340 * need to set the codec line out and mic 1 pin widgets to inputs
13341 */
13342static struct hda_verb alc861_threestack_ch2_init[] = {
13343 /* set pin widget 1Ah (line in) for input */
13344 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013345 /* set pin widget 18h (mic1/2) for input, for mic also enable
13346 * the vref
13347 */
Kailang Yangdf694da2005-12-05 19:42:22 +010013348 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13349
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013350 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
13351#if 0
13352 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
13353 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
13354#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010013355 { } /* end */
13356};
13357/*
13358 * 6ch mode
13359 * need to set the codec line out and mic 1 pin widgets to outputs
13360 */
13361static struct hda_verb alc861_threestack_ch6_init[] = {
13362 /* set pin widget 1Ah (line in) for output (Back Surround)*/
13363 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13364 /* set pin widget 18h (mic1) for output (CLFE)*/
13365 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13366
13367 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013368 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013369
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013370 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
13371#if 0
13372 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
13373 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
13374#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010013375 { } /* end */
13376};
13377
13378static struct hda_channel_mode alc861_threestack_modes[2] = {
13379 { 2, alc861_threestack_ch2_init },
13380 { 6, alc861_threestack_ch6_init },
13381};
Takashi Iwai22309c32006-08-09 16:57:28 +020013382/* Set mic1 as input and unmute the mixer */
13383static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
13384 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13385 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
13386 { } /* end */
13387};
13388/* Set mic1 as output and mute mixer */
13389static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
13390 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13391 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
13392 { } /* end */
13393};
13394
13395static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
13396 { 2, alc861_uniwill_m31_ch2_init },
13397 { 4, alc861_uniwill_m31_ch4_init },
13398};
Kailang Yangdf694da2005-12-05 19:42:22 +010013399
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013400/* Set mic1 and line-in as input and unmute the mixer */
13401static struct hda_verb alc861_asus_ch2_init[] = {
13402 /* set pin widget 1Ah (line in) for input */
13403 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013404 /* set pin widget 18h (mic1/2) for input, for mic also enable
13405 * the vref
13406 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013407 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13408
13409 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
13410#if 0
13411 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
13412 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
13413#endif
13414 { } /* end */
13415};
13416/* Set mic1 nad line-in as output and mute mixer */
13417static struct hda_verb alc861_asus_ch6_init[] = {
13418 /* set pin widget 1Ah (line in) for output (Back Surround)*/
13419 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13420 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
13421 /* set pin widget 18h (mic1) for output (CLFE)*/
13422 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13423 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
13424 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
13425 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
13426
13427 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
13428#if 0
13429 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
13430 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
13431#endif
13432 { } /* end */
13433};
13434
13435static struct hda_channel_mode alc861_asus_modes[2] = {
13436 { 2, alc861_asus_ch2_init },
13437 { 6, alc861_asus_ch6_init },
13438};
13439
Kailang Yangdf694da2005-12-05 19:42:22 +010013440/* patch-ALC861 */
13441
13442static struct snd_kcontrol_new alc861_base_mixer[] = {
13443 /* output mixer control */
13444 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13445 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
13446 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
13447 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
13448 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
13449
13450 /*Input mixer control */
13451 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
13452 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
13453 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13454 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
13455 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
13456 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
13457 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13458 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
13459 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
13460 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013461
Kailang Yangdf694da2005-12-05 19:42:22 +010013462 { } /* end */
13463};
13464
13465static struct snd_kcontrol_new alc861_3ST_mixer[] = {
13466 /* output mixer control */
13467 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13468 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
13469 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
13470 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
13471 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
13472
13473 /* Input mixer control */
13474 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
13475 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
13476 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13477 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
13478 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
13479 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
13480 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13481 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
13482 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
13483 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013484
Kailang Yangdf694da2005-12-05 19:42:22 +010013485 {
13486 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13487 .name = "Channel Mode",
13488 .info = alc_ch_mode_info,
13489 .get = alc_ch_mode_get,
13490 .put = alc_ch_mode_put,
13491 .private_value = ARRAY_SIZE(alc861_threestack_modes),
13492 },
13493 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013494};
13495
Takashi Iwaid1d985f2006-11-23 19:27:12 +010013496static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013497 /* output mixer control */
13498 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13499 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13500 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020013501
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013502 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013503};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013504
Takashi Iwai22309c32006-08-09 16:57:28 +020013505static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
13506 /* output mixer control */
13507 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13508 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
13509 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
13510 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
13511 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
13512
13513 /* Input mixer control */
13514 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
13515 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
13516 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13517 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
13518 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
13519 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
13520 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13521 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
13522 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
13523 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013524
Takashi Iwai22309c32006-08-09 16:57:28 +020013525 {
13526 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13527 .name = "Channel Mode",
13528 .info = alc_ch_mode_info,
13529 .get = alc_ch_mode_get,
13530 .put = alc_ch_mode_put,
13531 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
13532 },
13533 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013534};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013535
13536static struct snd_kcontrol_new alc861_asus_mixer[] = {
13537 /* output mixer control */
13538 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13539 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
13540 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
13541 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
13542 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
13543
13544 /* Input mixer control */
13545 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
13546 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
13547 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13548 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
13549 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
13550 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
13551 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13552 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
13553 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013554 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
13555
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013556 {
13557 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13558 .name = "Channel Mode",
13559 .info = alc_ch_mode_info,
13560 .get = alc_ch_mode_get,
13561 .put = alc_ch_mode_put,
13562 .private_value = ARRAY_SIZE(alc861_asus_modes),
13563 },
13564 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013565};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013566
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013567/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010013568static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013569 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13570 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013571 { }
13572};
13573
Kailang Yangdf694da2005-12-05 19:42:22 +010013574/*
13575 * generic initialization of ADC, input mixers and output mixers
13576 */
13577static struct hda_verb alc861_base_init_verbs[] = {
13578 /*
13579 * Unmute ADC0 and set the default input to mic-in
13580 */
13581 /* port-A for surround (rear panel) */
13582 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13583 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
13584 /* port-B for mic-in (rear panel) with vref */
13585 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13586 /* port-C for line-in (rear panel) */
13587 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13588 /* port-D for Front */
13589 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13590 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
13591 /* port-E for HP out (front panel) */
13592 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
13593 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010013594 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013595 /* port-F for mic-in (front panel) with vref */
13596 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13597 /* port-G for CLFE (rear panel) */
13598 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13599 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
13600 /* port-H for side (rear panel) */
13601 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13602 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
13603 /* CD-in */
13604 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13605 /* route front mic to ADC1*/
13606 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
13607 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013608
Kailang Yangdf694da2005-12-05 19:42:22 +010013609 /* Unmute DAC0~3 & spdif out*/
13610 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13611 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13612 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13613 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13614 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020013615
Kailang Yangdf694da2005-12-05 19:42:22 +010013616 /* Unmute Mixer 14 (mic) 1c (Line in)*/
13617 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13618 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13619 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13620 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013621
Kailang Yangdf694da2005-12-05 19:42:22 +010013622 /* Unmute Stereo Mixer 15 */
13623 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13624 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13625 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013626 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010013627
13628 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13629 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13630 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13631 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13632 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13633 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13634 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13635 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013636 /* hp used DAC 3 (Front) */
13637 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010013638 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13639
13640 { }
13641};
13642
13643static struct hda_verb alc861_threestack_init_verbs[] = {
13644 /*
13645 * Unmute ADC0 and set the default input to mic-in
13646 */
13647 /* port-A for surround (rear panel) */
13648 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13649 /* port-B for mic-in (rear panel) with vref */
13650 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13651 /* port-C for line-in (rear panel) */
13652 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13653 /* port-D for Front */
13654 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13655 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
13656 /* port-E for HP out (front panel) */
13657 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
13658 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010013659 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013660 /* port-F for mic-in (front panel) with vref */
13661 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13662 /* port-G for CLFE (rear panel) */
13663 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13664 /* port-H for side (rear panel) */
13665 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13666 /* CD-in */
13667 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13668 /* route front mic to ADC1*/
13669 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
13670 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13671 /* Unmute DAC0~3 & spdif out*/
13672 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13673 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13674 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13675 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13676 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020013677
Kailang Yangdf694da2005-12-05 19:42:22 +010013678 /* Unmute Mixer 14 (mic) 1c (Line in)*/
13679 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13680 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13681 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13682 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013683
Kailang Yangdf694da2005-12-05 19:42:22 +010013684 /* Unmute Stereo Mixer 15 */
13685 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13686 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13687 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013688 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010013689
13690 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13691 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13692 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13693 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13694 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13695 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13696 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13697 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013698 /* hp used DAC 3 (Front) */
13699 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010013700 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13701 { }
13702};
Takashi Iwai22309c32006-08-09 16:57:28 +020013703
13704static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
13705 /*
13706 * Unmute ADC0 and set the default input to mic-in
13707 */
13708 /* port-A for surround (rear panel) */
13709 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13710 /* port-B for mic-in (rear panel) with vref */
13711 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13712 /* port-C for line-in (rear panel) */
13713 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13714 /* port-D for Front */
13715 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13716 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
13717 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013718 /* this has to be set to VREF80 */
13719 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020013720 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010013721 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020013722 /* port-F for mic-in (front panel) with vref */
13723 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13724 /* port-G for CLFE (rear panel) */
13725 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13726 /* port-H for side (rear panel) */
13727 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13728 /* CD-in */
13729 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13730 /* route front mic to ADC1*/
13731 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
13732 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13733 /* Unmute DAC0~3 & spdif out*/
13734 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13735 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13736 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13737 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13738 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020013739
Takashi Iwai22309c32006-08-09 16:57:28 +020013740 /* Unmute Mixer 14 (mic) 1c (Line in)*/
13741 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13742 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13743 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13744 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013745
Takashi Iwai22309c32006-08-09 16:57:28 +020013746 /* Unmute Stereo Mixer 15 */
13747 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13748 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13749 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013750 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020013751
13752 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13753 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13754 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13755 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13756 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13757 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13758 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13759 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013760 /* hp used DAC 3 (Front) */
13761 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020013762 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13763 { }
13764};
13765
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013766static struct hda_verb alc861_asus_init_verbs[] = {
13767 /*
13768 * Unmute ADC0 and set the default input to mic-in
13769 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013770 /* port-A for surround (rear panel)
13771 * according to codec#0 this is the HP jack
13772 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013773 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
13774 /* route front PCM to HP */
13775 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
13776 /* port-B for mic-in (rear panel) with vref */
13777 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13778 /* port-C for line-in (rear panel) */
13779 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13780 /* port-D for Front */
13781 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13782 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
13783 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013784 /* this has to be set to VREF80 */
13785 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013786 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010013787 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013788 /* port-F for mic-in (front panel) with vref */
13789 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13790 /* port-G for CLFE (rear panel) */
13791 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13792 /* port-H for side (rear panel) */
13793 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13794 /* CD-in */
13795 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13796 /* route front mic to ADC1*/
13797 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
13798 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13799 /* Unmute DAC0~3 & spdif out*/
13800 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13801 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13802 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13803 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13804 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13805 /* Unmute Mixer 14 (mic) 1c (Line in)*/
13806 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13807 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13808 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13809 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013810
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013811 /* Unmute Stereo Mixer 15 */
13812 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13813 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13814 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013815 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013816
13817 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13818 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13819 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13820 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13821 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13822 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13823 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13824 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013825 /* hp used DAC 3 (Front) */
13826 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013827 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13828 { }
13829};
13830
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013831/* additional init verbs for ASUS laptops */
13832static struct hda_verb alc861_asus_laptop_init_verbs[] = {
13833 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
13834 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
13835 { }
13836};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013837
Kailang Yangdf694da2005-12-05 19:42:22 +010013838/*
13839 * generic initialization of ADC, input mixers and output mixers
13840 */
13841static struct hda_verb alc861_auto_init_verbs[] = {
13842 /*
13843 * Unmute ADC0 and set the default input to mic-in
13844 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013845 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010013846 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013847
Kailang Yangdf694da2005-12-05 19:42:22 +010013848 /* Unmute DAC0~3 & spdif out*/
13849 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13850 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13851 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13852 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13853 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020013854
Kailang Yangdf694da2005-12-05 19:42:22 +010013855 /* Unmute Mixer 14 (mic) 1c (Line in)*/
13856 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13857 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13858 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13859 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013860
Kailang Yangdf694da2005-12-05 19:42:22 +010013861 /* Unmute Stereo Mixer 15 */
13862 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13863 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13864 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13865 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
13866
13867 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13868 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13869 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13870 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13871 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13872 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13873 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13874 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13875
13876 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13877 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013878 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13879 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010013880 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13881 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013882 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13883 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010013884
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013885 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010013886
13887 { }
13888};
13889
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013890static struct hda_verb alc861_toshiba_init_verbs[] = {
13891 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013892
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013893 { }
13894};
13895
13896/* toggle speaker-output according to the hp-jack state */
13897static void alc861_toshiba_automute(struct hda_codec *codec)
13898{
13899 unsigned int present;
13900
13901 present = snd_hda_codec_read(codec, 0x0f, 0,
13902 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013903 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
13904 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
13905 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
13906 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013907}
13908
13909static void alc861_toshiba_unsol_event(struct hda_codec *codec,
13910 unsigned int res)
13911{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013912 if ((res >> 26) == ALC880_HP_EVENT)
13913 alc861_toshiba_automute(codec);
13914}
13915
Kailang Yangdf694da2005-12-05 19:42:22 +010013916/* pcm configuration: identiacal with ALC880 */
13917#define alc861_pcm_analog_playback alc880_pcm_analog_playback
13918#define alc861_pcm_analog_capture alc880_pcm_analog_capture
13919#define alc861_pcm_digital_playback alc880_pcm_digital_playback
13920#define alc861_pcm_digital_capture alc880_pcm_digital_capture
13921
13922
13923#define ALC861_DIGOUT_NID 0x07
13924
13925static struct hda_channel_mode alc861_8ch_modes[1] = {
13926 { 8, NULL }
13927};
13928
13929static hda_nid_t alc861_dac_nids[4] = {
13930 /* front, surround, clfe, side */
13931 0x03, 0x06, 0x05, 0x04
13932};
13933
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013934static hda_nid_t alc660_dac_nids[3] = {
13935 /* front, clfe, surround */
13936 0x03, 0x05, 0x06
13937};
13938
Kailang Yangdf694da2005-12-05 19:42:22 +010013939static hda_nid_t alc861_adc_nids[1] = {
13940 /* ADC0-2 */
13941 0x08,
13942};
13943
13944static struct hda_input_mux alc861_capture_source = {
13945 .num_items = 5,
13946 .items = {
13947 { "Mic", 0x0 },
13948 { "Front Mic", 0x3 },
13949 { "Line", 0x1 },
13950 { "CD", 0x4 },
13951 { "Mixer", 0x5 },
13952 },
13953};
13954
13955/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013956static int alc861_auto_fill_dac_nids(struct alc_spec *spec,
13957 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010013958{
13959 int i;
13960 hda_nid_t nid;
13961
13962 spec->multiout.dac_nids = spec->private_dac_nids;
13963 for (i = 0; i < cfg->line_outs; i++) {
13964 nid = cfg->line_out_pins[i];
13965 if (nid) {
13966 if (i >= ARRAY_SIZE(alc861_dac_nids))
13967 continue;
13968 spec->multiout.dac_nids[i] = alc861_dac_nids[i];
13969 }
13970 }
13971 spec->multiout.num_dacs = cfg->line_outs;
13972 return 0;
13973}
13974
13975/* add playback controls from the parsed DAC table */
13976static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec,
13977 const struct auto_pin_cfg *cfg)
13978{
13979 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013980 static const char *chname[4] = {
13981 "Front", "Surround", NULL /*CLFE*/, "Side"
13982 };
Kailang Yangdf694da2005-12-05 19:42:22 +010013983 hda_nid_t nid;
13984 int i, idx, err;
13985
13986 for (i = 0; i < cfg->line_outs; i++) {
13987 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013988 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010013989 continue;
13990 if (nid == 0x05) {
13991 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013992 err = add_control(spec, ALC_CTL_BIND_MUTE,
13993 "Center Playback Switch",
13994 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
13995 HDA_OUTPUT));
13996 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013997 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013998 err = add_control(spec, ALC_CTL_BIND_MUTE,
13999 "LFE Playback Switch",
14000 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
14001 HDA_OUTPUT));
14002 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010014003 return err;
14004 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014005 for (idx = 0; idx < ARRAY_SIZE(alc861_dac_nids) - 1;
14006 idx++)
Kailang Yangdf694da2005-12-05 19:42:22 +010014007 if (nid == alc861_dac_nids[idx])
14008 break;
14009 sprintf(name, "%s Playback Switch", chname[idx]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014010 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
14011 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
14012 HDA_OUTPUT));
14013 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010014014 return err;
14015 }
14016 }
14017 return 0;
14018}
14019
14020static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
14021{
14022 int err;
14023 hda_nid_t nid;
14024
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014025 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010014026 return 0;
14027
14028 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
14029 nid = 0x03;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014030 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
14031 "Headphone Playback Switch",
14032 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
14033 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010014034 return err;
14035 spec->multiout.hp_nid = nid;
14036 }
14037 return 0;
14038}
14039
14040/* create playback/capture controls for input pins */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014041static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec,
14042 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010014043{
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020014044 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010014045 int i, err, idx, idx1;
14046
14047 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014048 switch (cfg->input_pins[i]) {
Kailang Yangdf694da2005-12-05 19:42:22 +010014049 case 0x0c:
14050 idx1 = 1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014051 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010014052 break;
14053 case 0x0f:
14054 idx1 = 2;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014055 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010014056 break;
14057 case 0x0d:
14058 idx1 = 0;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014059 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010014060 break;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014061 case 0x10:
Kailang Yangdf694da2005-12-05 19:42:22 +010014062 idx1 = 3;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014063 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010014064 break;
14065 case 0x11:
14066 idx1 = 4;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014067 idx = 0; /* CD */
Kailang Yangdf694da2005-12-05 19:42:22 +010014068 break;
14069 default:
14070 continue;
14071 }
14072
Takashi Iwai4a471b72005-12-07 13:56:29 +010014073 err = new_analog_input(spec, cfg->input_pins[i],
14074 auto_pin_cfg_labels[i], idx, 0x15);
Kailang Yangdf694da2005-12-05 19:42:22 +010014075 if (err < 0)
14076 return err;
14077
Takashi Iwai4a471b72005-12-07 13:56:29 +010014078 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +010014079 imux->items[imux->num_items].index = idx1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014080 imux->num_items++;
Kailang Yangdf694da2005-12-05 19:42:22 +010014081 }
14082 return 0;
14083}
14084
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014085static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
14086 hda_nid_t nid,
Kailang Yangdf694da2005-12-05 19:42:22 +010014087 int pin_type, int dac_idx)
14088{
Jacek Luczak564c5be2008-05-03 18:41:23 +020014089 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
14090 pin_type);
14091 snd_hda_codec_write(codec, dac_idx, 0, AC_VERB_SET_AMP_GAIN_MUTE,
14092 AMP_OUT_UNMUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +010014093}
14094
14095static void alc861_auto_init_multi_out(struct hda_codec *codec)
14096{
14097 struct alc_spec *spec = codec->spec;
14098 int i;
14099
14100 for (i = 0; i < spec->autocfg.line_outs; i++) {
14101 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020014102 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010014103 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020014104 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014105 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010014106 }
14107}
14108
14109static void alc861_auto_init_hp_out(struct hda_codec *codec)
14110{
14111 struct alc_spec *spec = codec->spec;
14112 hda_nid_t pin;
14113
Takashi Iwaieb06ed82006-09-20 17:10:27 +020014114 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010014115 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014116 alc861_auto_set_output_and_unmute(codec, pin, PIN_HP,
14117 spec->multiout.dac_nids[0]);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014118 pin = spec->autocfg.speaker_pins[0];
14119 if (pin)
14120 alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010014121}
14122
14123static void alc861_auto_init_analog_input(struct hda_codec *codec)
14124{
14125 struct alc_spec *spec = codec->spec;
14126 int i;
14127
14128 for (i = 0; i < AUTO_PIN_LAST; i++) {
14129 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai23f0c042009-02-26 13:03:58 +010014130 if (nid >= 0x0c && nid <= 0x11)
14131 alc_set_input_pin(codec, nid, i);
Kailang Yangdf694da2005-12-05 19:42:22 +010014132 }
14133}
14134
14135/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014136/* return 1 if successful, 0 if the proper config is not found,
14137 * or a negative error code
14138 */
Kailang Yangdf694da2005-12-05 19:42:22 +010014139static int alc861_parse_auto_config(struct hda_codec *codec)
14140{
14141 struct alc_spec *spec = codec->spec;
14142 int err;
14143 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
14144
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014145 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
14146 alc861_ignore);
14147 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010014148 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014149 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010014150 return 0; /* can't find valid BIOS pin config */
14151
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014152 err = alc861_auto_fill_dac_nids(spec, &spec->autocfg);
14153 if (err < 0)
14154 return err;
14155 err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg);
14156 if (err < 0)
14157 return err;
14158 err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
14159 if (err < 0)
14160 return err;
14161 err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg);
14162 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010014163 return err;
14164
14165 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
14166
Takashi Iwai0852d7a2009-02-11 11:35:15 +010014167 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010014168 spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
14169
Takashi Iwai603c4012008-07-30 15:01:44 +020014170 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010014171 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010014172
Takashi Iwaid88897e2008-10-31 15:01:37 +010014173 add_verb(spec, alc861_auto_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +010014174
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020014175 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020014176 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010014177
14178 spec->adc_nids = alc861_adc_nids;
14179 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010014180 set_capture_mixer(spec);
Kailang Yangdf694da2005-12-05 19:42:22 +010014181
Takashi Iwai4a79ba342009-04-22 16:31:35 +020014182 alc_ssid_check(codec, 0x0e, 0x0f, 0x0b);
14183
Kailang Yangdf694da2005-12-05 19:42:22 +010014184 return 1;
14185}
14186
Takashi Iwaiae6b8132006-03-03 16:47:17 +010014187/* additional initialization for auto-configuration model */
14188static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010014189{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014190 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010014191 alc861_auto_init_multi_out(codec);
14192 alc861_auto_init_hp_out(codec);
14193 alc861_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014194 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020014195 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010014196}
14197
Takashi Iwaicb53c622007-08-10 17:21:45 +020014198#ifdef CONFIG_SND_HDA_POWER_SAVE
14199static struct hda_amp_list alc861_loopbacks[] = {
14200 { 0x15, HDA_INPUT, 0 },
14201 { 0x15, HDA_INPUT, 1 },
14202 { 0x15, HDA_INPUT, 2 },
14203 { 0x15, HDA_INPUT, 3 },
14204 { } /* end */
14205};
14206#endif
14207
Kailang Yangdf694da2005-12-05 19:42:22 +010014208
14209/*
14210 * configuration and preset
14211 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010014212static const char *alc861_models[ALC861_MODEL_LAST] = {
14213 [ALC861_3ST] = "3stack",
14214 [ALC660_3ST] = "3stack-660",
14215 [ALC861_3ST_DIG] = "3stack-dig",
14216 [ALC861_6ST_DIG] = "6stack-dig",
14217 [ALC861_UNIWILL_M31] = "uniwill-m31",
14218 [ALC861_TOSHIBA] = "toshiba",
14219 [ALC861_ASUS] = "asus",
14220 [ALC861_ASUS_LAPTOP] = "asus-laptop",
14221 [ALC861_AUTO] = "auto",
14222};
14223
14224static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010014225 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010014226 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
14227 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
14228 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010014229 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020014230 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010014231 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020014232 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
14233 * Any other models that need this preset?
14234 */
14235 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020014236 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
14237 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010014238 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
14239 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
14240 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
14241 /* FIXME: the below seems conflict */
14242 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
14243 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
14244 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010014245 {}
14246};
14247
14248static struct alc_config_preset alc861_presets[] = {
14249 [ALC861_3ST] = {
14250 .mixers = { alc861_3ST_mixer },
14251 .init_verbs = { alc861_threestack_init_verbs },
14252 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14253 .dac_nids = alc861_dac_nids,
14254 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
14255 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020014256 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010014257 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14258 .adc_nids = alc861_adc_nids,
14259 .input_mux = &alc861_capture_source,
14260 },
14261 [ALC861_3ST_DIG] = {
14262 .mixers = { alc861_base_mixer },
14263 .init_verbs = { alc861_threestack_init_verbs },
14264 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14265 .dac_nids = alc861_dac_nids,
14266 .dig_out_nid = ALC861_DIGOUT_NID,
14267 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
14268 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020014269 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010014270 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14271 .adc_nids = alc861_adc_nids,
14272 .input_mux = &alc861_capture_source,
14273 },
14274 [ALC861_6ST_DIG] = {
14275 .mixers = { alc861_base_mixer },
14276 .init_verbs = { alc861_base_init_verbs },
14277 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14278 .dac_nids = alc861_dac_nids,
14279 .dig_out_nid = ALC861_DIGOUT_NID,
14280 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
14281 .channel_mode = alc861_8ch_modes,
14282 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14283 .adc_nids = alc861_adc_nids,
14284 .input_mux = &alc861_capture_source,
14285 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014286 [ALC660_3ST] = {
14287 .mixers = { alc861_3ST_mixer },
14288 .init_verbs = { alc861_threestack_init_verbs },
14289 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
14290 .dac_nids = alc660_dac_nids,
14291 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
14292 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020014293 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014294 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14295 .adc_nids = alc861_adc_nids,
14296 .input_mux = &alc861_capture_source,
14297 },
Takashi Iwai22309c32006-08-09 16:57:28 +020014298 [ALC861_UNIWILL_M31] = {
14299 .mixers = { alc861_uniwill_m31_mixer },
14300 .init_verbs = { alc861_uniwill_m31_init_verbs },
14301 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14302 .dac_nids = alc861_dac_nids,
14303 .dig_out_nid = ALC861_DIGOUT_NID,
14304 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
14305 .channel_mode = alc861_uniwill_m31_modes,
14306 .need_dac_fix = 1,
14307 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14308 .adc_nids = alc861_adc_nids,
14309 .input_mux = &alc861_capture_source,
14310 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014311 [ALC861_TOSHIBA] = {
14312 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014313 .init_verbs = { alc861_base_init_verbs,
14314 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014315 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14316 .dac_nids = alc861_dac_nids,
14317 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
14318 .channel_mode = alc883_3ST_2ch_modes,
14319 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14320 .adc_nids = alc861_adc_nids,
14321 .input_mux = &alc861_capture_source,
14322 .unsol_event = alc861_toshiba_unsol_event,
14323 .init_hook = alc861_toshiba_automute,
14324 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014325 [ALC861_ASUS] = {
14326 .mixers = { alc861_asus_mixer },
14327 .init_verbs = { alc861_asus_init_verbs },
14328 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14329 .dac_nids = alc861_dac_nids,
14330 .dig_out_nid = ALC861_DIGOUT_NID,
14331 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
14332 .channel_mode = alc861_asus_modes,
14333 .need_dac_fix = 1,
14334 .hp_nid = 0x06,
14335 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14336 .adc_nids = alc861_adc_nids,
14337 .input_mux = &alc861_capture_source,
14338 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014339 [ALC861_ASUS_LAPTOP] = {
14340 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
14341 .init_verbs = { alc861_asus_init_verbs,
14342 alc861_asus_laptop_init_verbs },
14343 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14344 .dac_nids = alc861_dac_nids,
14345 .dig_out_nid = ALC861_DIGOUT_NID,
14346 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
14347 .channel_mode = alc883_3ST_2ch_modes,
14348 .need_dac_fix = 1,
14349 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14350 .adc_nids = alc861_adc_nids,
14351 .input_mux = &alc861_capture_source,
14352 },
14353};
Kailang Yangdf694da2005-12-05 19:42:22 +010014354
14355
14356static int patch_alc861(struct hda_codec *codec)
14357{
14358 struct alc_spec *spec;
14359 int board_config;
14360 int err;
14361
Robert P. J. Daydc041e02006-12-19 14:44:15 +010014362 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010014363 if (spec == NULL)
14364 return -ENOMEM;
14365
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014366 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010014367
Takashi Iwaif5fcc132006-11-24 17:07:44 +010014368 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
14369 alc861_models,
14370 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014371
Takashi Iwaif5fcc132006-11-24 17:07:44 +010014372 if (board_config < 0) {
Takashi Iwai6c627f32009-05-18 12:33:36 +020014373 printk(KERN_INFO "hda_codec: Unknown model for %s, "
14374 "trying auto-probe from BIOS...\n", codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010014375 board_config = ALC861_AUTO;
14376 }
14377
14378 if (board_config == ALC861_AUTO) {
14379 /* automatic parse from the BIOS config */
14380 err = alc861_parse_auto_config(codec);
14381 if (err < 0) {
14382 alc_free(codec);
14383 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014384 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014385 printk(KERN_INFO
14386 "hda_codec: Cannot set up configuration "
14387 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010014388 board_config = ALC861_3ST_DIG;
14389 }
14390 }
14391
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090014392 err = snd_hda_attach_beep_device(codec, 0x23);
14393 if (err < 0) {
14394 alc_free(codec);
14395 return err;
14396 }
14397
Kailang Yangdf694da2005-12-05 19:42:22 +010014398 if (board_config != ALC861_AUTO)
14399 setup_preset(spec, &alc861_presets[board_config]);
14400
Kailang Yangdf694da2005-12-05 19:42:22 +010014401 spec->stream_analog_playback = &alc861_pcm_analog_playback;
14402 spec->stream_analog_capture = &alc861_pcm_analog_capture;
14403
Kailang Yangdf694da2005-12-05 19:42:22 +010014404 spec->stream_digital_playback = &alc861_pcm_digital_playback;
14405 spec->stream_digital_capture = &alc861_pcm_digital_capture;
14406
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010014407 set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
14408
Takashi Iwai2134ea42008-01-10 16:53:55 +010014409 spec->vmaster_nid = 0x03;
14410
Kailang Yangdf694da2005-12-05 19:42:22 +010014411 codec->patch_ops = alc_patch_ops;
14412 if (board_config == ALC861_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010014413 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020014414#ifdef CONFIG_SND_HDA_POWER_SAVE
14415 if (!spec->loopback.amplist)
14416 spec->loopback.amplist = alc861_loopbacks;
14417#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010014418 codec->proc_widget_hook = print_realtek_coef;
Kailang Yangea1fb292008-08-26 12:58:38 +020014419
Kailang Yangdf694da2005-12-05 19:42:22 +010014420 return 0;
14421}
14422
14423/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014424 * ALC861-VD support
14425 *
14426 * Based on ALC882
14427 *
14428 * In addition, an independent DAC
14429 */
14430#define ALC861VD_DIGOUT_NID 0x06
14431
14432static hda_nid_t alc861vd_dac_nids[4] = {
14433 /* front, surr, clfe, side surr */
14434 0x02, 0x03, 0x04, 0x05
14435};
14436
14437/* dac_nids for ALC660vd are in a different order - according to
14438 * Realtek's driver.
14439 * This should probably tesult in a different mixer for 6stack models
14440 * of ALC660vd codecs, but for now there is only 3stack mixer
14441 * - and it is the same as in 861vd.
14442 * adc_nids in ALC660vd are (is) the same as in 861vd
14443 */
14444static hda_nid_t alc660vd_dac_nids[3] = {
14445 /* front, rear, clfe, rear_surr */
14446 0x02, 0x04, 0x03
14447};
14448
14449static hda_nid_t alc861vd_adc_nids[1] = {
14450 /* ADC0 */
14451 0x09,
14452};
14453
Takashi Iwaie1406342008-02-11 18:32:32 +010014454static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
14455
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014456/* input MUX */
14457/* FIXME: should be a matrix-type input source selection */
14458static struct hda_input_mux alc861vd_capture_source = {
14459 .num_items = 4,
14460 .items = {
14461 { "Mic", 0x0 },
14462 { "Front Mic", 0x1 },
14463 { "Line", 0x2 },
14464 { "CD", 0x4 },
14465 },
14466};
14467
Kailang Yang272a5272007-05-14 11:00:38 +020014468static struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010014469 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020014470 .items = {
Tobin Davisb419f342008-03-07 11:57:51 +010014471 { "Ext Mic", 0x0 },
14472 { "Int Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020014473 },
14474};
14475
Kailang Yangd1a991a2007-08-15 16:21:59 +020014476static struct hda_input_mux alc861vd_hp_capture_source = {
14477 .num_items = 2,
14478 .items = {
14479 { "Front Mic", 0x0 },
14480 { "ATAPI Mic", 0x1 },
14481 },
14482};
14483
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014484/*
14485 * 2ch mode
14486 */
14487static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
14488 { 2, NULL }
14489};
14490
14491/*
14492 * 6ch mode
14493 */
14494static struct hda_verb alc861vd_6stack_ch6_init[] = {
14495 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14496 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14497 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14498 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14499 { } /* end */
14500};
14501
14502/*
14503 * 8ch mode
14504 */
14505static struct hda_verb alc861vd_6stack_ch8_init[] = {
14506 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14507 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14508 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14509 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14510 { } /* end */
14511};
14512
14513static struct hda_channel_mode alc861vd_6stack_modes[2] = {
14514 { 6, alc861vd_6stack_ch6_init },
14515 { 8, alc861vd_6stack_ch8_init },
14516};
14517
14518static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
14519 {
14520 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14521 .name = "Channel Mode",
14522 .info = alc_ch_mode_info,
14523 .get = alc_ch_mode_get,
14524 .put = alc_ch_mode_put,
14525 },
14526 { } /* end */
14527};
14528
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014529/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
14530 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
14531 */
14532static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
14533 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14534 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
14535
14536 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14537 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
14538
14539 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
14540 HDA_OUTPUT),
14541 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
14542 HDA_OUTPUT),
14543 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
14544 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
14545
14546 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
14547 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
14548
14549 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14550
14551 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
14552 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14553 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14554
14555 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
14556 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14557 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14558
14559 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14560 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14561
14562 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
14563 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
14564
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014565 { } /* end */
14566};
14567
14568static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
14569 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14570 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
14571
14572 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14573
14574 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
14575 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14576 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14577
14578 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
14579 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14580 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14581
14582 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14583 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14584
14585 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
14586 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
14587
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014588 { } /* end */
14589};
14590
Kailang Yangbdd148a2007-05-08 15:19:08 +020014591static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
14592 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14593 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
14594 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14595
14596 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14597
14598 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
14599 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14600 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14601
14602 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
14603 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14604 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14605
14606 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
14607 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
14608
14609 { } /* end */
14610};
14611
Tobin Davisb419f342008-03-07 11:57:51 +010014612/* Pin assignment: Speaker=0x14, HP = 0x15,
14613 * Ext Mic=0x18, Int Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020014614 */
14615static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010014616 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14617 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020014618 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14619 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisb419f342008-03-07 11:57:51 +010014620 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
14621 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14622 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14623 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
14624 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14625 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020014626 { } /* end */
14627};
14628
Kailang Yangd1a991a2007-08-15 16:21:59 +020014629/* Pin assignment: Speaker=0x14, Line-out = 0x15,
14630 * Front Mic=0x18, ATAPI Mic = 0x19,
14631 */
14632static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
14633 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14634 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
14635 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14636 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
14637 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14638 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14639 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14640 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020014641
Kailang Yangd1a991a2007-08-15 16:21:59 +020014642 { } /* end */
14643};
14644
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014645/*
14646 * generic initialization of ADC, input mixers and output mixers
14647 */
14648static struct hda_verb alc861vd_volume_init_verbs[] = {
14649 /*
14650 * Unmute ADC0 and set the default input to mic-in
14651 */
14652 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
14653 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14654
14655 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
14656 * the analog-loopback mixer widget
14657 */
14658 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020014659 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14660 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14661 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
14662 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
14663 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014664
14665 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020014666 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14667 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14668 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014669 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014670
14671 /*
14672 * Set up output mixers (0x02 - 0x05)
14673 */
14674 /* set vol=0 to output mixers */
14675 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14676 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14677 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14678 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14679
14680 /* set up input amps for analog loopback */
14681 /* Amp Indices: DAC = 0, mixer = 1 */
14682 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14683 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14684 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14685 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14686 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14687 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14688 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14689 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14690
14691 { }
14692};
14693
14694/*
14695 * 3-stack pin configuration:
14696 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
14697 */
14698static struct hda_verb alc861vd_3stack_init_verbs[] = {
14699 /*
14700 * Set pin mode and muting
14701 */
14702 /* set front pin widgets 0x14 for output */
14703 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14704 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14705 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
14706
14707 /* Mic (rear) pin: input vref at 80% */
14708 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14709 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14710 /* Front Mic pin: input vref at 80% */
14711 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14712 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14713 /* Line In pin: input */
14714 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14715 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14716 /* Line-2 In: Headphone output (output 0 - 0x0c) */
14717 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14718 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14719 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
14720 /* CD pin widget for input */
14721 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14722
14723 { }
14724};
14725
14726/*
14727 * 6-stack pin configuration:
14728 */
14729static struct hda_verb alc861vd_6stack_init_verbs[] = {
14730 /*
14731 * Set pin mode and muting
14732 */
14733 /* set front pin widgets 0x14 for output */
14734 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14735 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14736 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
14737
14738 /* Rear Pin: output 1 (0x0d) */
14739 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14740 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14741 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14742 /* CLFE Pin: output 2 (0x0e) */
14743 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14744 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14745 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
14746 /* Side Pin: output 3 (0x0f) */
14747 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14748 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14749 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
14750
14751 /* Mic (rear) pin: input vref at 80% */
14752 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14753 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14754 /* Front Mic pin: input vref at 80% */
14755 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14756 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14757 /* Line In pin: input */
14758 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14759 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14760 /* Line-2 In: Headphone output (output 0 - 0x0c) */
14761 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14762 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14763 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
14764 /* CD pin widget for input */
14765 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14766
14767 { }
14768};
14769
Kailang Yangbdd148a2007-05-08 15:19:08 +020014770static struct hda_verb alc861vd_eapd_verbs[] = {
14771 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
14772 { }
14773};
14774
Kailang Yangf9423e72008-05-27 12:32:25 +020014775static struct hda_verb alc660vd_eapd_verbs[] = {
14776 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
14777 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
14778 { }
14779};
14780
Kailang Yangbdd148a2007-05-08 15:19:08 +020014781static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
14782 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14783 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14784 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
14785 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020014786 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020014787 {}
14788};
14789
Kailang Yangbdd148a2007-05-08 15:19:08 +020014790static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
14791{
14792 unsigned int present;
14793 unsigned char bits;
14794
14795 present = snd_hda_codec_read(codec, 0x18, 0,
14796 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020014797 bits = present ? HDA_AMP_MUTE : 0;
14798 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
14799 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020014800}
14801
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020014802static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
Kailang Yangbdd148a2007-05-08 15:19:08 +020014803{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020014804 struct alc_spec *spec = codec->spec;
14805
14806 spec->autocfg.hp_pins[0] = 0x1b;
14807 spec->autocfg.speaker_pins[0] = 0x14;
14808 alc_automute_amp(codec);
Kailang Yangbdd148a2007-05-08 15:19:08 +020014809 alc861vd_lenovo_mic_automute(codec);
14810}
14811
14812static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
14813 unsigned int res)
14814{
14815 switch (res >> 26) {
Kailang Yangbdd148a2007-05-08 15:19:08 +020014816 case ALC880_MIC_EVENT:
14817 alc861vd_lenovo_mic_automute(codec);
14818 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020014819 default:
14820 alc_automute_amp_unsol_event(codec, res);
14821 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +020014822 }
14823}
14824
Kailang Yang272a5272007-05-14 11:00:38 +020014825static struct hda_verb alc861vd_dallas_verbs[] = {
14826 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14827 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14828 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14829 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14830
14831 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14832 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14833 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14834 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14835 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14836 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14837 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14838 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014839
Kailang Yang272a5272007-05-14 11:00:38 +020014840 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14841 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14842 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14843 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14844 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14845 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14846 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14847 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14848
14849 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
14850 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14851 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
14852 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14853 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14854 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14855 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14856 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14857
14858 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14859 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
14860 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
14861 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
14862
14863 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014864 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020014865 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14866
14867 { } /* end */
14868};
14869
14870/* toggle speaker-output according to the hp-jack state */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020014871static void alc861vd_dallas_init_hook(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +020014872{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020014873 struct alc_spec *spec = codec->spec;
Kailang Yang272a5272007-05-14 11:00:38 +020014874
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020014875 spec->autocfg.hp_pins[0] = 0x15;
14876 spec->autocfg.speaker_pins[0] = 0x14;
14877 alc_automute_amp(codec);
Kailang Yang272a5272007-05-14 11:00:38 +020014878}
14879
Takashi Iwaicb53c622007-08-10 17:21:45 +020014880#ifdef CONFIG_SND_HDA_POWER_SAVE
14881#define alc861vd_loopbacks alc880_loopbacks
14882#endif
14883
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014884/* pcm configuration: identiacal with ALC880 */
14885#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
14886#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
14887#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
14888#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
14889
14890/*
14891 * configuration and preset
14892 */
14893static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
14894 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020014895 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Takashi Iwai13c94742008-11-05 08:06:08 +010014896 [ALC660VD_ASUS_V1S] = "asus-v1s",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014897 [ALC861VD_3ST] = "3stack",
14898 [ALC861VD_3ST_DIG] = "3stack-digout",
14899 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020014900 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020014901 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020014902 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014903 [ALC861VD_AUTO] = "auto",
14904};
14905
14906static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010014907 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
14908 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010014909 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014910 SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
Takashi Iwai13c94742008-11-05 08:06:08 +010014911 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
Mike Crash6963f842007-06-25 12:12:51 +020014912 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014913 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010014914 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020014915 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Kailang Yang272a5272007-05-14 11:00:38 +020014916 SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS),
Takashi Iwai542d7c62007-08-16 18:57:30 +020014917 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010014918 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020014919 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010014920 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020014921 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014922 {}
14923};
14924
14925static struct alc_config_preset alc861vd_presets[] = {
14926 [ALC660VD_3ST] = {
14927 .mixers = { alc861vd_3st_mixer },
14928 .init_verbs = { alc861vd_volume_init_verbs,
14929 alc861vd_3stack_init_verbs },
14930 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14931 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014932 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14933 .channel_mode = alc861vd_3stack_2ch_modes,
14934 .input_mux = &alc861vd_capture_source,
14935 },
Mike Crash6963f842007-06-25 12:12:51 +020014936 [ALC660VD_3ST_DIG] = {
14937 .mixers = { alc861vd_3st_mixer },
14938 .init_verbs = { alc861vd_volume_init_verbs,
14939 alc861vd_3stack_init_verbs },
14940 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14941 .dac_nids = alc660vd_dac_nids,
14942 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020014943 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14944 .channel_mode = alc861vd_3stack_2ch_modes,
14945 .input_mux = &alc861vd_capture_source,
14946 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014947 [ALC861VD_3ST] = {
14948 .mixers = { alc861vd_3st_mixer },
14949 .init_verbs = { alc861vd_volume_init_verbs,
14950 alc861vd_3stack_init_verbs },
14951 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14952 .dac_nids = alc861vd_dac_nids,
14953 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14954 .channel_mode = alc861vd_3stack_2ch_modes,
14955 .input_mux = &alc861vd_capture_source,
14956 },
14957 [ALC861VD_3ST_DIG] = {
14958 .mixers = { alc861vd_3st_mixer },
14959 .init_verbs = { alc861vd_volume_init_verbs,
14960 alc861vd_3stack_init_verbs },
14961 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14962 .dac_nids = alc861vd_dac_nids,
14963 .dig_out_nid = ALC861VD_DIGOUT_NID,
14964 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14965 .channel_mode = alc861vd_3stack_2ch_modes,
14966 .input_mux = &alc861vd_capture_source,
14967 },
14968 [ALC861VD_6ST_DIG] = {
14969 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
14970 .init_verbs = { alc861vd_volume_init_verbs,
14971 alc861vd_6stack_init_verbs },
14972 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14973 .dac_nids = alc861vd_dac_nids,
14974 .dig_out_nid = ALC861VD_DIGOUT_NID,
14975 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
14976 .channel_mode = alc861vd_6stack_modes,
14977 .input_mux = &alc861vd_capture_source,
14978 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020014979 [ALC861VD_LENOVO] = {
14980 .mixers = { alc861vd_lenovo_mixer },
14981 .init_verbs = { alc861vd_volume_init_verbs,
14982 alc861vd_3stack_init_verbs,
14983 alc861vd_eapd_verbs,
14984 alc861vd_lenovo_unsol_verbs },
14985 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14986 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020014987 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14988 .channel_mode = alc861vd_3stack_2ch_modes,
14989 .input_mux = &alc861vd_capture_source,
14990 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020014991 .init_hook = alc861vd_lenovo_init_hook,
Kailang Yangbdd148a2007-05-08 15:19:08 +020014992 },
Kailang Yang272a5272007-05-14 11:00:38 +020014993 [ALC861VD_DALLAS] = {
14994 .mixers = { alc861vd_dallas_mixer },
14995 .init_verbs = { alc861vd_dallas_verbs },
14996 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14997 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020014998 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14999 .channel_mode = alc861vd_3stack_2ch_modes,
15000 .input_mux = &alc861vd_dallas_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015001 .unsol_event = alc_automute_amp_unsol_event,
15002 .init_hook = alc861vd_dallas_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020015003 },
15004 [ALC861VD_HP] = {
15005 .mixers = { alc861vd_hp_mixer },
15006 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
15007 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
15008 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020015009 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020015010 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
15011 .channel_mode = alc861vd_3stack_2ch_modes,
15012 .input_mux = &alc861vd_hp_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015013 .unsol_event = alc_automute_amp_unsol_event,
15014 .init_hook = alc861vd_dallas_init_hook,
Kailang Yangea1fb292008-08-26 12:58:38 +020015015 },
Takashi Iwai13c94742008-11-05 08:06:08 +010015016 [ALC660VD_ASUS_V1S] = {
15017 .mixers = { alc861vd_lenovo_mixer },
15018 .init_verbs = { alc861vd_volume_init_verbs,
15019 alc861vd_3stack_init_verbs,
15020 alc861vd_eapd_verbs,
15021 alc861vd_lenovo_unsol_verbs },
15022 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
15023 .dac_nids = alc660vd_dac_nids,
15024 .dig_out_nid = ALC861VD_DIGOUT_NID,
15025 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
15026 .channel_mode = alc861vd_3stack_2ch_modes,
15027 .input_mux = &alc861vd_capture_source,
15028 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015029 .init_hook = alc861vd_lenovo_init_hook,
Takashi Iwai13c94742008-11-05 08:06:08 +010015030 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015031};
15032
15033/*
15034 * BIOS auto configuration
15035 */
15036static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
15037 hda_nid_t nid, int pin_type, int dac_idx)
15038{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015039 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015040}
15041
15042static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
15043{
15044 struct alc_spec *spec = codec->spec;
15045 int i;
15046
15047 for (i = 0; i <= HDA_SIDE; i++) {
15048 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015049 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015050 if (nid)
15051 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015052 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015053 }
15054}
15055
15056
15057static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
15058{
15059 struct alc_spec *spec = codec->spec;
15060 hda_nid_t pin;
15061
15062 pin = spec->autocfg.hp_pins[0];
15063 if (pin) /* connect to front and use dac 0 */
15064 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015065 pin = spec->autocfg.speaker_pins[0];
15066 if (pin)
15067 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015068}
15069
15070#define alc861vd_is_input_pin(nid) alc880_is_input_pin(nid)
15071#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
15072
15073static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
15074{
15075 struct alc_spec *spec = codec->spec;
15076 int i;
15077
15078 for (i = 0; i < AUTO_PIN_LAST; i++) {
15079 hda_nid_t nid = spec->autocfg.input_pins[i];
15080 if (alc861vd_is_input_pin(nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +010015081 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +010015082 if (nid != ALC861VD_PIN_CD_NID &&
15083 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015084 snd_hda_codec_write(codec, nid, 0,
15085 AC_VERB_SET_AMP_GAIN_MUTE,
15086 AMP_OUT_MUTE);
15087 }
15088 }
15089}
15090
Takashi Iwaif511b012008-08-15 16:46:42 +020015091#define alc861vd_auto_init_input_src alc882_auto_init_input_src
15092
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015093#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
15094#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
15095
15096/* add playback controls from the parsed DAC table */
15097/* Based on ALC880 version. But ALC861VD has separate,
15098 * different NIDs for mute/unmute switch and volume control */
15099static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
15100 const struct auto_pin_cfg *cfg)
15101{
15102 char name[32];
15103 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
15104 hda_nid_t nid_v, nid_s;
15105 int i, err;
15106
15107 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015108 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015109 continue;
15110 nid_v = alc861vd_idx_to_mixer_vol(
15111 alc880_dac_to_idx(
15112 spec->multiout.dac_nids[i]));
15113 nid_s = alc861vd_idx_to_mixer_switch(
15114 alc880_dac_to_idx(
15115 spec->multiout.dac_nids[i]));
15116
15117 if (i == 2) {
15118 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015119 err = add_control(spec, ALC_CTL_WIDGET_VOL,
15120 "Center Playback Volume",
15121 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
15122 HDA_OUTPUT));
15123 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015124 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015125 err = add_control(spec, ALC_CTL_WIDGET_VOL,
15126 "LFE Playback Volume",
15127 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
15128 HDA_OUTPUT));
15129 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015130 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015131 err = add_control(spec, ALC_CTL_BIND_MUTE,
15132 "Center Playback Switch",
15133 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
15134 HDA_INPUT));
15135 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015136 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015137 err = add_control(spec, ALC_CTL_BIND_MUTE,
15138 "LFE Playback Switch",
15139 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
15140 HDA_INPUT));
15141 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015142 return err;
15143 } else {
15144 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015145 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
15146 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
15147 HDA_OUTPUT));
15148 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015149 return err;
15150 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015151 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
Kailang Yangbdd148a2007-05-08 15:19:08 +020015152 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015153 HDA_INPUT));
15154 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015155 return err;
15156 }
15157 }
15158 return 0;
15159}
15160
15161/* add playback controls for speaker and HP outputs */
15162/* Based on ALC880 version. But ALC861VD has separate,
15163 * different NIDs for mute/unmute switch and volume control */
15164static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
15165 hda_nid_t pin, const char *pfx)
15166{
15167 hda_nid_t nid_v, nid_s;
15168 int err;
15169 char name[32];
15170
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015171 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015172 return 0;
15173
15174 if (alc880_is_fixed_pin(pin)) {
15175 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
15176 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015177 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015178 spec->multiout.hp_nid = nid_v;
15179 else
15180 spec->multiout.extra_out_nid[0] = nid_v;
15181 /* control HP volume/switch on the output mixer amp */
15182 nid_v = alc861vd_idx_to_mixer_vol(
15183 alc880_fixed_pin_idx(pin));
15184 nid_s = alc861vd_idx_to_mixer_switch(
15185 alc880_fixed_pin_idx(pin));
15186
15187 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015188 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
15189 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
15190 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015191 return err;
15192 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015193 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
15194 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
15195 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015196 return err;
15197 } else if (alc880_is_multi_pin(pin)) {
15198 /* set manual connection */
15199 /* we have only a switch on HP-out PIN */
15200 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015201 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
15202 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
15203 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015204 return err;
15205 }
15206 return 0;
15207}
15208
15209/* parse the BIOS configuration and set up the alc_spec
15210 * return 1 if successful, 0 if the proper config is not found,
15211 * or a negative error code
15212 * Based on ALC880 version - had to change it to override
15213 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
15214static int alc861vd_parse_auto_config(struct hda_codec *codec)
15215{
15216 struct alc_spec *spec = codec->spec;
15217 int err;
15218 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
15219
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015220 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
15221 alc861vd_ignore);
15222 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015223 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015224 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015225 return 0; /* can't find valid BIOS pin config */
15226
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015227 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
15228 if (err < 0)
15229 return err;
15230 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
15231 if (err < 0)
15232 return err;
15233 err = alc861vd_auto_create_extra_out(spec,
15234 spec->autocfg.speaker_pins[0],
15235 "Speaker");
15236 if (err < 0)
15237 return err;
15238 err = alc861vd_auto_create_extra_out(spec,
15239 spec->autocfg.hp_pins[0],
15240 "Headphone");
15241 if (err < 0)
15242 return err;
15243 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
15244 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015245 return err;
15246
15247 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
15248
Takashi Iwai0852d7a2009-02-11 11:35:15 +010015249 if (spec->autocfg.dig_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015250 spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
15251
Takashi Iwai603c4012008-07-30 15:01:44 +020015252 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010015253 add_mixer(spec, spec->kctls.list);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015254
Takashi Iwaid88897e2008-10-31 15:01:37 +010015255 add_verb(spec, alc861vd_volume_init_verbs);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015256
15257 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020015258 spec->input_mux = &spec->private_imux[0];
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015259
Takashi Iwai776e1842007-08-29 15:07:11 +020015260 err = alc_auto_add_mic_boost(codec);
15261 if (err < 0)
15262 return err;
15263
Takashi Iwai4a79ba342009-04-22 16:31:35 +020015264 alc_ssid_check(codec, 0x15, 0x1b, 0x14);
15265
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015266 return 1;
15267}
15268
15269/* additional initialization for auto-configuration model */
15270static void alc861vd_auto_init(struct hda_codec *codec)
15271{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015272 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015273 alc861vd_auto_init_multi_out(codec);
15274 alc861vd_auto_init_hp_out(codec);
15275 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020015276 alc861vd_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015277 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020015278 alc_inithook(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015279}
15280
15281static int patch_alc861vd(struct hda_codec *codec)
15282{
15283 struct alc_spec *spec;
15284 int err, board_config;
15285
15286 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
15287 if (spec == NULL)
15288 return -ENOMEM;
15289
15290 codec->spec = spec;
15291
15292 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
15293 alc861vd_models,
15294 alc861vd_cfg_tbl);
15295
15296 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
Takashi Iwai6c627f32009-05-18 12:33:36 +020015297 printk(KERN_INFO "hda_codec: Unknown model for %s, "
15298 "trying auto-probe from BIOS...\n", codec->chip_name);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015299 board_config = ALC861VD_AUTO;
15300 }
15301
15302 if (board_config == ALC861VD_AUTO) {
15303 /* automatic parse from the BIOS config */
15304 err = alc861vd_parse_auto_config(codec);
15305 if (err < 0) {
15306 alc_free(codec);
15307 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015308 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015309 printk(KERN_INFO
15310 "hda_codec: Cannot set up configuration "
15311 "from BIOS. Using base mode...\n");
15312 board_config = ALC861VD_3ST;
15313 }
15314 }
15315
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090015316 err = snd_hda_attach_beep_device(codec, 0x23);
15317 if (err < 0) {
15318 alc_free(codec);
15319 return err;
15320 }
15321
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015322 if (board_config != ALC861VD_AUTO)
15323 setup_preset(spec, &alc861vd_presets[board_config]);
15324
Kailang Yang2f893282008-05-27 12:14:47 +020015325 if (codec->vendor_id == 0x10ec0660) {
Kailang Yangf9423e72008-05-27 12:32:25 +020015326 /* always turn on EAPD */
Takashi Iwaid88897e2008-10-31 15:01:37 +010015327 add_verb(spec, alc660vd_eapd_verbs);
Kailang Yang2f893282008-05-27 12:14:47 +020015328 }
15329
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015330 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
15331 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
15332
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015333 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
15334 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
15335
15336 spec->adc_nids = alc861vd_adc_nids;
15337 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +010015338 spec->capsrc_nids = alc861vd_capsrc_nids;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020015339 spec->capture_style = CAPT_MIX;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015340
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015341 set_capture_mixer(spec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010015342 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015343
Takashi Iwai2134ea42008-01-10 16:53:55 +010015344 spec->vmaster_nid = 0x02;
15345
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015346 codec->patch_ops = alc_patch_ops;
15347
15348 if (board_config == ALC861VD_AUTO)
15349 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020015350#ifdef CONFIG_SND_HDA_POWER_SAVE
15351 if (!spec->loopback.amplist)
15352 spec->loopback.amplist = alc861vd_loopbacks;
15353#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010015354 codec->proc_widget_hook = print_realtek_coef;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015355
15356 return 0;
15357}
15358
15359/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015360 * ALC662 support
15361 *
15362 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
15363 * configuration. Each pin widget can choose any input DACs and a mixer.
15364 * Each ADC is connected from a mixer of all inputs. This makes possible
15365 * 6-channel independent captures.
15366 *
15367 * In addition, an independent DAC for the multi-playback (not used in this
15368 * driver yet).
15369 */
15370#define ALC662_DIGOUT_NID 0x06
15371#define ALC662_DIGIN_NID 0x0a
15372
15373static hda_nid_t alc662_dac_nids[4] = {
15374 /* front, rear, clfe, rear_surr */
15375 0x02, 0x03, 0x04
15376};
15377
Kailang Yang622e84c2009-04-21 07:39:04 +020015378static hda_nid_t alc272_dac_nids[2] = {
15379 0x02, 0x03
15380};
15381
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015382static hda_nid_t alc662_adc_nids[1] = {
15383 /* ADC1-2 */
15384 0x09,
15385};
Takashi Iwaie1406342008-02-11 18:32:32 +010015386
Kailang Yang622e84c2009-04-21 07:39:04 +020015387static hda_nid_t alc272_adc_nids[1] = {
15388 /* ADC1-2 */
15389 0x08,
15390};
15391
Kailang Yang77a261b2008-02-19 11:38:05 +010015392static hda_nid_t alc662_capsrc_nids[1] = { 0x22 };
Kailang Yang622e84c2009-04-21 07:39:04 +020015393static hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
15394
Takashi Iwaie1406342008-02-11 18:32:32 +010015395
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015396/* input MUX */
15397/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015398static struct hda_input_mux alc662_capture_source = {
15399 .num_items = 4,
15400 .items = {
15401 { "Mic", 0x0 },
15402 { "Front Mic", 0x1 },
15403 { "Line", 0x2 },
15404 { "CD", 0x4 },
15405 },
15406};
15407
15408static struct hda_input_mux alc662_lenovo_101e_capture_source = {
15409 .num_items = 2,
15410 .items = {
15411 { "Mic", 0x1 },
15412 { "Line", 0x2 },
15413 },
15414};
Kailang Yang291702f2007-10-16 14:28:03 +020015415
15416static struct hda_input_mux alc662_eeepc_capture_source = {
15417 .num_items = 2,
15418 .items = {
15419 { "i-Mic", 0x1 },
15420 { "e-Mic", 0x0 },
15421 },
15422};
15423
Kailang Yang6dda9f42008-05-27 12:05:31 +020015424static struct hda_input_mux alc663_capture_source = {
15425 .num_items = 3,
15426 .items = {
15427 { "Mic", 0x0 },
15428 { "Front Mic", 0x1 },
15429 { "Line", 0x2 },
15430 },
15431};
15432
15433static struct hda_input_mux alc663_m51va_capture_source = {
15434 .num_items = 2,
15435 .items = {
15436 { "Ext-Mic", 0x0 },
15437 { "D-Mic", 0x9 },
15438 },
15439};
15440
Chris Pockelé9541ba12009-05-12 08:08:53 +020015441#if 1 /* set to 0 for testing other input sources below */
15442static struct hda_input_mux alc272_nc10_capture_source = {
15443 .num_items = 2,
15444 .items = {
15445 { "Autoselect Mic", 0x0 },
15446 { "Internal Mic", 0x1 },
15447 },
15448};
15449#else
15450static struct hda_input_mux alc272_nc10_capture_source = {
15451 .num_items = 16,
15452 .items = {
15453 { "Autoselect Mic", 0x0 },
15454 { "Internal Mic", 0x1 },
15455 { "In-0x02", 0x2 },
15456 { "In-0x03", 0x3 },
15457 { "In-0x04", 0x4 },
15458 { "In-0x05", 0x5 },
15459 { "In-0x06", 0x6 },
15460 { "In-0x07", 0x7 },
15461 { "In-0x08", 0x8 },
15462 { "In-0x09", 0x9 },
15463 { "In-0x0a", 0x0a },
15464 { "In-0x0b", 0x0b },
15465 { "In-0x0c", 0x0c },
15466 { "In-0x0d", 0x0d },
15467 { "In-0x0e", 0x0e },
15468 { "In-0x0f", 0x0f },
15469 },
15470};
15471#endif
15472
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015473/*
15474 * 2ch mode
15475 */
15476static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
15477 { 2, NULL }
15478};
15479
15480/*
15481 * 2ch mode
15482 */
15483static struct hda_verb alc662_3ST_ch2_init[] = {
15484 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
15485 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
15486 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
15487 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
15488 { } /* end */
15489};
15490
15491/*
15492 * 6ch mode
15493 */
15494static struct hda_verb alc662_3ST_ch6_init[] = {
15495 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15496 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
15497 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
15498 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15499 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
15500 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
15501 { } /* end */
15502};
15503
15504static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
15505 { 2, alc662_3ST_ch2_init },
15506 { 6, alc662_3ST_ch6_init },
15507};
15508
15509/*
15510 * 2ch mode
15511 */
15512static struct hda_verb alc662_sixstack_ch6_init[] = {
15513 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15514 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15515 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15516 { } /* end */
15517};
15518
15519/*
15520 * 6ch mode
15521 */
15522static struct hda_verb alc662_sixstack_ch8_init[] = {
15523 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15524 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15525 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15526 { } /* end */
15527};
15528
15529static struct hda_channel_mode alc662_5stack_modes[2] = {
15530 { 2, alc662_sixstack_ch6_init },
15531 { 6, alc662_sixstack_ch8_init },
15532};
15533
15534/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
15535 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
15536 */
15537
15538static struct snd_kcontrol_new alc662_base_mixer[] = {
15539 /* output mixer control */
15540 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015541 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015542 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015543 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015544 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
15545 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015546 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
15547 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015548 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15549
15550 /*Input mixer control */
15551 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
15552 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
15553 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
15554 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
15555 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
15556 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
15557 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
15558 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015559 { } /* end */
15560};
15561
15562static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
15563 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015564 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015565 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15566 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
15567 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
15568 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15569 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15570 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15571 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15572 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15573 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015574 { } /* end */
15575};
15576
15577static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
15578 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015579 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015580 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015581 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015582 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
15583 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015584 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
15585 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015586 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15587 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
15588 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
15589 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15590 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15591 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15592 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15593 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15594 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015595 { } /* end */
15596};
15597
15598static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
15599 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15600 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010015601 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15602 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015603 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15604 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15605 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15606 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15607 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015608 { } /* end */
15609};
15610
Kailang Yang291702f2007-10-16 14:28:03 +020015611static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020015612 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15613 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang291702f2007-10-16 14:28:03 +020015614
15615 HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
15616 HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15617 HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15618
15619 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
15620 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15621 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15622 { } /* end */
15623};
15624
Kailang Yang8c427222008-01-10 13:03:59 +010015625static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020015626 ALC262_HIPPO_MASTER_SWITCH,
15627 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010015628 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010015629 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
15630 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010015631 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
15632 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15633 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15634 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15635 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15636 { } /* end */
15637};
15638
Kailang Yangf1d4e282008-08-26 14:03:29 +020015639static struct hda_bind_ctls alc663_asus_bind_master_vol = {
15640 .ops = &snd_hda_bind_vol,
15641 .values = {
15642 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
15643 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
15644 0
15645 },
15646};
15647
15648static struct hda_bind_ctls alc663_asus_one_bind_switch = {
15649 .ops = &snd_hda_bind_sw,
15650 .values = {
15651 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
15652 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
15653 0
15654 },
15655};
15656
Kailang Yang6dda9f42008-05-27 12:05:31 +020015657static struct snd_kcontrol_new alc663_m51va_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020015658 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
15659 HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
15660 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15661 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15662 { } /* end */
15663};
15664
15665static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
15666 .ops = &snd_hda_bind_sw,
15667 .values = {
15668 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
15669 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
15670 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
15671 0
15672 },
15673};
15674
15675static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
15676 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
15677 HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
15678 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15679 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15680 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15681 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15682
15683 { } /* end */
15684};
15685
15686static struct hda_bind_ctls alc663_asus_four_bind_switch = {
15687 .ops = &snd_hda_bind_sw,
15688 .values = {
15689 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
15690 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
15691 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
15692 0
15693 },
15694};
15695
15696static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
15697 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
15698 HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
15699 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15700 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15701 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15702 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15703 { } /* end */
15704};
15705
15706static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020015707 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15708 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020015709 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15710 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15711 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15712 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15713 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15714 { } /* end */
15715};
15716
15717static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
15718 .ops = &snd_hda_bind_vol,
15719 .values = {
15720 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
15721 HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
15722 0
15723 },
15724};
15725
15726static struct hda_bind_ctls alc663_asus_two_bind_switch = {
15727 .ops = &snd_hda_bind_sw,
15728 .values = {
15729 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
15730 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
15731 0
15732 },
15733};
15734
15735static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
15736 HDA_BIND_VOL("Master Playback Volume",
15737 &alc663_asus_two_bind_master_vol),
15738 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
15739 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020015740 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
15741 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15742 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020015743 { } /* end */
15744};
15745
15746static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
15747 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
15748 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
15749 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15750 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
15751 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15752 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020015753 { } /* end */
15754};
15755
15756static struct snd_kcontrol_new alc663_g71v_mixer[] = {
15757 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15758 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
15759 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15760 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
15761 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
15762
15763 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15764 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15765 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15766 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15767 { } /* end */
15768};
15769
15770static struct snd_kcontrol_new alc663_g50v_mixer[] = {
15771 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15772 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
15773 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
15774
15775 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15776 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15777 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15778 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15779 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15780 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15781 { } /* end */
15782};
15783
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015784static struct snd_kcontrol_new alc662_chmode_mixer[] = {
15785 {
15786 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15787 .name = "Channel Mode",
15788 .info = alc_ch_mode_info,
15789 .get = alc_ch_mode_get,
15790 .put = alc_ch_mode_put,
15791 },
15792 { } /* end */
15793};
15794
15795static struct hda_verb alc662_init_verbs[] = {
15796 /* ADC: mute amp left and right */
15797 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15798 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
15799 /* Front mixer: unmute input/output amp left and right (volume = 0) */
15800
Takashi Iwaicb53c622007-08-10 17:21:45 +020015801 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15802 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15803 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15804 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
15805 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015806
Kailang Yangb60dd392007-09-20 12:50:29 +020015807 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15808 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15809 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15810 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15811 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15812 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015813
15814 /* Front Pin: output 0 (0x0c) */
15815 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15816 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15817
15818 /* Rear Pin: output 1 (0x0d) */
15819 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15820 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15821
15822 /* CLFE Pin: output 2 (0x0e) */
15823 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15824 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15825
15826 /* Mic (rear) pin: input vref at 80% */
15827 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
15828 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15829 /* Front Mic pin: input vref at 80% */
15830 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
15831 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15832 /* Line In pin: input */
15833 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15834 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15835 /* Line-2 In: Headphone output (output 0 - 0x0c) */
15836 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15837 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15838 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
15839 /* CD pin widget for input */
15840 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15841
15842 /* FIXME: use matrix-type input source selection */
15843 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
15844 /* Input mixer */
15845 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang291702f2007-10-16 14:28:03 +020015846 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020015847
15848 /* always trun on EAPD */
15849 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
15850 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
15851
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015852 { }
15853};
15854
15855static struct hda_verb alc662_sue_init_verbs[] = {
15856 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
15857 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020015858 {}
15859};
15860
15861static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
15862 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15863 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15864 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015865};
15866
Kailang Yang8c427222008-01-10 13:03:59 +010015867/* Set Unsolicited Event*/
15868static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
15869 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15870 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15871 {}
15872};
15873
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015874/*
15875 * generic initialization of ADC, input mixers and output mixers
15876 */
15877static struct hda_verb alc662_auto_init_verbs[] = {
15878 /*
15879 * Unmute ADC and set the default input to mic-in
15880 */
15881 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
15882 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15883
15884 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
15885 * mixer widget
15886 * Note: PASD motherboards uses the Line In 2 as the input for front
15887 * panel mic (mic 2)
15888 */
15889 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020015890 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15891 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15892 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15893 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
15894 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015895
15896 /*
15897 * Set up output mixers (0x0c - 0x0f)
15898 */
15899 /* set vol=0 to output mixers */
15900 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15901 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15902 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15903
15904 /* set up input amps for analog loopback */
15905 /* Amp Indices: DAC = 0, mixer = 1 */
Kailang Yangb60dd392007-09-20 12:50:29 +020015906 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15907 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15908 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15909 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15910 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15911 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015912
15913
15914 /* FIXME: use matrix-type input source selection */
15915 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
15916 /* Input mixer */
15917 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangd1a991a2007-08-15 16:21:59 +020015918 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015919 { }
15920};
15921
Takashi Iwai24fb9172008-09-02 14:48:20 +020015922/* additional verbs for ALC663 */
15923static struct hda_verb alc663_auto_init_verbs[] = {
15924 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15925 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15926 { }
15927};
15928
Kailang Yang6dda9f42008-05-27 12:05:31 +020015929static struct hda_verb alc663_m51va_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020015930 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15931 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yang6dda9f42008-05-27 12:05:31 +020015932 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15933 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf1d4e282008-08-26 14:03:29 +020015934 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15935 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15936 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020015937 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15938 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15939 {}
15940};
15941
Kailang Yangf1d4e282008-08-26 14:03:29 +020015942static struct hda_verb alc663_21jd_amic_init_verbs[] = {
15943 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15944 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15945 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15946 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15947 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15948 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15949 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15950 {}
15951};
15952
15953static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
15954 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15955 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15956 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15957 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
15958 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15959 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15960 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15961 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15962 {}
15963};
15964
15965static struct hda_verb alc663_15jd_amic_init_verbs[] = {
15966 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15967 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15968 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15969 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15970 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15971 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15972 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15973 {}
15974};
15975
15976static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
15977 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15978 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15979 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15980 {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
15981 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15982 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15983 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
15984 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15985 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15986 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15987 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15988 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15989 {}
15990};
15991
15992static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
15993 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15994 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15995 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15996 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15997 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15998 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15999 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
16000 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16001 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16002 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16003 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16004 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16005 {}
16006};
16007
Kailang Yang6dda9f42008-05-27 12:05:31 +020016008static struct hda_verb alc663_g71v_init_verbs[] = {
16009 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16010 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
16011 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
16012
16013 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16014 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16015 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
16016
16017 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
16018 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
16019 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
16020 {}
16021};
16022
16023static struct hda_verb alc663_g50v_init_verbs[] = {
16024 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16025 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16026 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
16027
16028 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16029 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16030 {}
16031};
16032
Kailang Yangf1d4e282008-08-26 14:03:29 +020016033static struct hda_verb alc662_ecs_init_verbs[] = {
16034 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
16035 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16036 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16037 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16038 {}
16039};
16040
Kailang Yang622e84c2009-04-21 07:39:04 +020016041static struct hda_verb alc272_dell_zm1_init_verbs[] = {
16042 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16043 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16044 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16045 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16046 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16047 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16048 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
16049 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16050 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
16051 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16052 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16053 {}
16054};
16055
16056static struct hda_verb alc272_dell_init_verbs[] = {
16057 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16058 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16059 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16060 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16061 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16062 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16063 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
16064 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16065 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
16066 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16067 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16068 {}
16069};
16070
Kailang Yangf1d4e282008-08-26 14:03:29 +020016071static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
16072 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
16073 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
16074 { } /* end */
16075};
16076
Kailang Yang622e84c2009-04-21 07:39:04 +020016077static struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
16078 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
16079 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
16080 { } /* end */
16081};
16082
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016083static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
16084{
16085 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016086 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016087
16088 present = snd_hda_codec_read(codec, 0x14, 0,
16089 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020016090 bits = present ? HDA_AMP_MUTE : 0;
16091 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
16092 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016093}
16094
16095static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
16096{
16097 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016098 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016099
16100 present = snd_hda_codec_read(codec, 0x1b, 0,
16101 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020016102 bits = present ? HDA_AMP_MUTE : 0;
16103 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
16104 HDA_AMP_MUTE, bits);
16105 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
16106 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016107}
16108
16109static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
16110 unsigned int res)
16111{
16112 if ((res >> 26) == ALC880_HP_EVENT)
16113 alc662_lenovo_101e_all_automute(codec);
16114 if ((res >> 26) == ALC880_FRONT_EVENT)
16115 alc662_lenovo_101e_ispeaker_automute(codec);
16116}
16117
Kailang Yang291702f2007-10-16 14:28:03 +020016118static void alc662_eeepc_mic_automute(struct hda_codec *codec)
16119{
16120 unsigned int present;
16121
16122 present = snd_hda_codec_read(codec, 0x18, 0,
16123 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
16124 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
16125 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
16126 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
16127 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
16128 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
16129 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
16130 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
16131 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
16132}
16133
16134/* unsolicited event for HP jack sensing */
16135static void alc662_eeepc_unsol_event(struct hda_codec *codec,
16136 unsigned int res)
16137{
Kailang Yang291702f2007-10-16 14:28:03 +020016138 if ((res >> 26) == ALC880_MIC_EVENT)
16139 alc662_eeepc_mic_automute(codec);
Takashi Iwai42171c12009-05-08 14:11:43 +020016140 else
16141 alc262_hippo_unsol_event(codec, res);
Kailang Yang291702f2007-10-16 14:28:03 +020016142}
16143
16144static void alc662_eeepc_inithook(struct hda_codec *codec)
16145{
Takashi Iwai42171c12009-05-08 14:11:43 +020016146 alc262_hippo1_init_hook(codec);
Kailang Yang291702f2007-10-16 14:28:03 +020016147 alc662_eeepc_mic_automute(codec);
16148}
16149
Kailang Yang8c427222008-01-10 13:03:59 +010016150static void alc662_eeepc_ep20_inithook(struct hda_codec *codec)
16151{
Takashi Iwai42171c12009-05-08 14:11:43 +020016152 struct alc_spec *spec = codec->spec;
16153
16154 spec->autocfg.hp_pins[0] = 0x14;
16155 spec->autocfg.speaker_pins[0] = 0x1b;
16156 alc262_hippo_master_update(codec);
Kailang Yang8c427222008-01-10 13:03:59 +010016157}
16158
Kailang Yang6dda9f42008-05-27 12:05:31 +020016159static void alc663_m51va_speaker_automute(struct hda_codec *codec)
16160{
16161 unsigned int present;
16162 unsigned char bits;
16163
16164 present = snd_hda_codec_read(codec, 0x21, 0,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016165 AC_VERB_GET_PIN_SENSE, 0)
16166 & AC_PINSENSE_PRESENCE;
Kailang Yang6dda9f42008-05-27 12:05:31 +020016167 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yangf1d4e282008-08-26 14:03:29 +020016168 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
16169 AMP_IN_MUTE(0), bits);
16170 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
16171 AMP_IN_MUTE(0), bits);
16172}
16173
16174static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
16175{
16176 unsigned int present;
16177 unsigned char bits;
16178
16179 present = snd_hda_codec_read(codec, 0x21, 0,
16180 AC_VERB_GET_PIN_SENSE, 0)
16181 & AC_PINSENSE_PRESENCE;
16182 bits = present ? HDA_AMP_MUTE : 0;
16183 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
16184 AMP_IN_MUTE(0), bits);
16185 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
16186 AMP_IN_MUTE(0), bits);
16187 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
16188 AMP_IN_MUTE(0), bits);
16189 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
16190 AMP_IN_MUTE(0), bits);
16191}
16192
16193static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
16194{
16195 unsigned int present;
16196 unsigned char bits;
16197
16198 present = snd_hda_codec_read(codec, 0x15, 0,
16199 AC_VERB_GET_PIN_SENSE, 0)
16200 & AC_PINSENSE_PRESENCE;
16201 bits = present ? HDA_AMP_MUTE : 0;
16202 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
16203 AMP_IN_MUTE(0), bits);
16204 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
16205 AMP_IN_MUTE(0), bits);
16206 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
16207 AMP_IN_MUTE(0), bits);
16208 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
16209 AMP_IN_MUTE(0), bits);
16210}
16211
16212static void alc662_f5z_speaker_automute(struct hda_codec *codec)
16213{
16214 unsigned int present;
16215 unsigned char bits;
16216
16217 present = snd_hda_codec_read(codec, 0x1b, 0,
16218 AC_VERB_GET_PIN_SENSE, 0)
16219 & AC_PINSENSE_PRESENCE;
16220 bits = present ? 0 : PIN_OUT;
16221 snd_hda_codec_write(codec, 0x14, 0,
16222 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
16223}
16224
16225static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
16226{
16227 unsigned int present1, present2;
16228
16229 present1 = snd_hda_codec_read(codec, 0x21, 0,
16230 AC_VERB_GET_PIN_SENSE, 0)
16231 & AC_PINSENSE_PRESENCE;
16232 present2 = snd_hda_codec_read(codec, 0x15, 0,
16233 AC_VERB_GET_PIN_SENSE, 0)
16234 & AC_PINSENSE_PRESENCE;
16235
16236 if (present1 || present2) {
16237 snd_hda_codec_write_cache(codec, 0x14, 0,
16238 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
16239 } else {
16240 snd_hda_codec_write_cache(codec, 0x14, 0,
16241 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
16242 }
16243}
16244
16245static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
16246{
16247 unsigned int present1, present2;
16248
16249 present1 = snd_hda_codec_read(codec, 0x1b, 0,
16250 AC_VERB_GET_PIN_SENSE, 0)
16251 & AC_PINSENSE_PRESENCE;
16252 present2 = snd_hda_codec_read(codec, 0x15, 0,
16253 AC_VERB_GET_PIN_SENSE, 0)
16254 & AC_PINSENSE_PRESENCE;
16255
16256 if (present1 || present2) {
16257 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
16258 AMP_IN_MUTE(0), AMP_IN_MUTE(0));
16259 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
16260 AMP_IN_MUTE(0), AMP_IN_MUTE(0));
16261 } else {
16262 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
16263 AMP_IN_MUTE(0), 0);
16264 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
16265 AMP_IN_MUTE(0), 0);
16266 }
Kailang Yang6dda9f42008-05-27 12:05:31 +020016267}
16268
16269static void alc663_m51va_mic_automute(struct hda_codec *codec)
16270{
16271 unsigned int present;
16272
16273 present = snd_hda_codec_read(codec, 0x18, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020016274 AC_VERB_GET_PIN_SENSE, 0)
16275 & AC_PINSENSE_PRESENCE;
Kailang Yang6dda9f42008-05-27 12:05:31 +020016276 snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020016277 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
Kailang Yang6dda9f42008-05-27 12:05:31 +020016278 snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020016279 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
Kailang Yang6dda9f42008-05-27 12:05:31 +020016280 snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020016281 0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
Kailang Yang6dda9f42008-05-27 12:05:31 +020016282 snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020016283 0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
Kailang Yang6dda9f42008-05-27 12:05:31 +020016284}
16285
16286static void alc663_m51va_unsol_event(struct hda_codec *codec,
16287 unsigned int res)
16288{
16289 switch (res >> 26) {
16290 case ALC880_HP_EVENT:
16291 alc663_m51va_speaker_automute(codec);
16292 break;
16293 case ALC880_MIC_EVENT:
16294 alc663_m51va_mic_automute(codec);
16295 break;
16296 }
16297}
16298
16299static void alc663_m51va_inithook(struct hda_codec *codec)
16300{
16301 alc663_m51va_speaker_automute(codec);
16302 alc663_m51va_mic_automute(codec);
16303}
16304
Kailang Yangf1d4e282008-08-26 14:03:29 +020016305/* ***************** Mode1 ******************************/
16306static void alc663_mode1_unsol_event(struct hda_codec *codec,
16307 unsigned int res)
16308{
16309 switch (res >> 26) {
16310 case ALC880_HP_EVENT:
16311 alc663_m51va_speaker_automute(codec);
16312 break;
16313 case ALC880_MIC_EVENT:
16314 alc662_eeepc_mic_automute(codec);
16315 break;
16316 }
16317}
16318
16319static void alc663_mode1_inithook(struct hda_codec *codec)
16320{
16321 alc663_m51va_speaker_automute(codec);
16322 alc662_eeepc_mic_automute(codec);
16323}
16324/* ***************** Mode2 ******************************/
16325static void alc662_mode2_unsol_event(struct hda_codec *codec,
16326 unsigned int res)
16327{
16328 switch (res >> 26) {
16329 case ALC880_HP_EVENT:
16330 alc662_f5z_speaker_automute(codec);
16331 break;
16332 case ALC880_MIC_EVENT:
16333 alc662_eeepc_mic_automute(codec);
16334 break;
16335 }
16336}
16337
16338static void alc662_mode2_inithook(struct hda_codec *codec)
16339{
16340 alc662_f5z_speaker_automute(codec);
16341 alc662_eeepc_mic_automute(codec);
16342}
16343/* ***************** Mode3 ******************************/
16344static void alc663_mode3_unsol_event(struct hda_codec *codec,
16345 unsigned int res)
16346{
16347 switch (res >> 26) {
16348 case ALC880_HP_EVENT:
16349 alc663_two_hp_m1_speaker_automute(codec);
16350 break;
16351 case ALC880_MIC_EVENT:
16352 alc662_eeepc_mic_automute(codec);
16353 break;
16354 }
16355}
16356
16357static void alc663_mode3_inithook(struct hda_codec *codec)
16358{
16359 alc663_two_hp_m1_speaker_automute(codec);
16360 alc662_eeepc_mic_automute(codec);
16361}
16362/* ***************** Mode4 ******************************/
16363static void alc663_mode4_unsol_event(struct hda_codec *codec,
16364 unsigned int res)
16365{
16366 switch (res >> 26) {
16367 case ALC880_HP_EVENT:
16368 alc663_21jd_two_speaker_automute(codec);
16369 break;
16370 case ALC880_MIC_EVENT:
16371 alc662_eeepc_mic_automute(codec);
16372 break;
16373 }
16374}
16375
16376static void alc663_mode4_inithook(struct hda_codec *codec)
16377{
16378 alc663_21jd_two_speaker_automute(codec);
16379 alc662_eeepc_mic_automute(codec);
16380}
16381/* ***************** Mode5 ******************************/
16382static void alc663_mode5_unsol_event(struct hda_codec *codec,
16383 unsigned int res)
16384{
16385 switch (res >> 26) {
16386 case ALC880_HP_EVENT:
16387 alc663_15jd_two_speaker_automute(codec);
16388 break;
16389 case ALC880_MIC_EVENT:
16390 alc662_eeepc_mic_automute(codec);
16391 break;
16392 }
16393}
16394
16395static void alc663_mode5_inithook(struct hda_codec *codec)
16396{
16397 alc663_15jd_two_speaker_automute(codec);
16398 alc662_eeepc_mic_automute(codec);
16399}
16400/* ***************** Mode6 ******************************/
16401static void alc663_mode6_unsol_event(struct hda_codec *codec,
16402 unsigned int res)
16403{
16404 switch (res >> 26) {
16405 case ALC880_HP_EVENT:
16406 alc663_two_hp_m2_speaker_automute(codec);
16407 break;
16408 case ALC880_MIC_EVENT:
16409 alc662_eeepc_mic_automute(codec);
16410 break;
16411 }
16412}
16413
16414static void alc663_mode6_inithook(struct hda_codec *codec)
16415{
16416 alc663_two_hp_m2_speaker_automute(codec);
16417 alc662_eeepc_mic_automute(codec);
16418}
16419
Kailang Yang6dda9f42008-05-27 12:05:31 +020016420static void alc663_g71v_hp_automute(struct hda_codec *codec)
16421{
16422 unsigned int present;
16423 unsigned char bits;
16424
16425 present = snd_hda_codec_read(codec, 0x21, 0,
16426 AC_VERB_GET_PIN_SENSE, 0)
16427 & AC_PINSENSE_PRESENCE;
16428 bits = present ? HDA_AMP_MUTE : 0;
16429 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
16430 HDA_AMP_MUTE, bits);
16431 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
16432 HDA_AMP_MUTE, bits);
16433}
16434
16435static void alc663_g71v_front_automute(struct hda_codec *codec)
16436{
16437 unsigned int present;
16438 unsigned char bits;
16439
16440 present = snd_hda_codec_read(codec, 0x15, 0,
16441 AC_VERB_GET_PIN_SENSE, 0)
16442 & AC_PINSENSE_PRESENCE;
16443 bits = present ? HDA_AMP_MUTE : 0;
16444 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
16445 HDA_AMP_MUTE, bits);
16446}
16447
16448static void alc663_g71v_unsol_event(struct hda_codec *codec,
16449 unsigned int res)
16450{
16451 switch (res >> 26) {
16452 case ALC880_HP_EVENT:
16453 alc663_g71v_hp_automute(codec);
16454 break;
16455 case ALC880_FRONT_EVENT:
16456 alc663_g71v_front_automute(codec);
16457 break;
16458 case ALC880_MIC_EVENT:
16459 alc662_eeepc_mic_automute(codec);
16460 break;
16461 }
16462}
16463
16464static void alc663_g71v_inithook(struct hda_codec *codec)
16465{
16466 alc663_g71v_front_automute(codec);
16467 alc663_g71v_hp_automute(codec);
16468 alc662_eeepc_mic_automute(codec);
16469}
16470
16471static void alc663_g50v_unsol_event(struct hda_codec *codec,
16472 unsigned int res)
16473{
16474 switch (res >> 26) {
16475 case ALC880_HP_EVENT:
16476 alc663_m51va_speaker_automute(codec);
16477 break;
16478 case ALC880_MIC_EVENT:
16479 alc662_eeepc_mic_automute(codec);
16480 break;
16481 }
16482}
16483
16484static void alc663_g50v_inithook(struct hda_codec *codec)
16485{
16486 alc663_m51va_speaker_automute(codec);
16487 alc662_eeepc_mic_automute(codec);
16488}
16489
Kailang Yangf1d4e282008-08-26 14:03:29 +020016490static struct snd_kcontrol_new alc662_ecs_mixer[] = {
16491 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020016492 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016493
16494 HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT),
16495 HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
16496 HDA_CODEC_MUTE("e-Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
16497
16498 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
16499 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16500 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16501 { } /* end */
16502};
16503
Chris Pockelé9541ba12009-05-12 08:08:53 +020016504static struct snd_kcontrol_new alc272_nc10_mixer[] = {
16505 /* Master Playback automatically created from Speaker and Headphone */
16506 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16507 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
16508 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16509 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
16510
16511 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16512 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16513 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
16514
16515 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16516 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16517 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
16518 { } /* end */
16519};
16520
Takashi Iwaicb53c622007-08-10 17:21:45 +020016521#ifdef CONFIG_SND_HDA_POWER_SAVE
16522#define alc662_loopbacks alc880_loopbacks
16523#endif
16524
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016525
16526/* pcm configuration: identiacal with ALC880 */
16527#define alc662_pcm_analog_playback alc880_pcm_analog_playback
16528#define alc662_pcm_analog_capture alc880_pcm_analog_capture
16529#define alc662_pcm_digital_playback alc880_pcm_digital_playback
16530#define alc662_pcm_digital_capture alc880_pcm_digital_capture
16531
16532/*
16533 * configuration and preset
16534 */
16535static const char *alc662_models[ALC662_MODEL_LAST] = {
16536 [ALC662_3ST_2ch_DIG] = "3stack-dig",
16537 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
16538 [ALC662_3ST_6ch] = "3stack-6ch",
16539 [ALC662_5ST_DIG] = "6stack-dig",
16540 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020016541 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010016542 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangf1d4e282008-08-26 14:03:29 +020016543 [ALC662_ECS] = "ecs",
Kailang Yang6dda9f42008-05-27 12:05:31 +020016544 [ALC663_ASUS_M51VA] = "m51va",
16545 [ALC663_ASUS_G71V] = "g71v",
16546 [ALC663_ASUS_H13] = "h13",
16547 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangf1d4e282008-08-26 14:03:29 +020016548 [ALC663_ASUS_MODE1] = "asus-mode1",
16549 [ALC662_ASUS_MODE2] = "asus-mode2",
16550 [ALC663_ASUS_MODE3] = "asus-mode3",
16551 [ALC663_ASUS_MODE4] = "asus-mode4",
16552 [ALC663_ASUS_MODE5] = "asus-mode5",
16553 [ALC663_ASUS_MODE6] = "asus-mode6",
Takashi Iwai01f2bd42009-05-11 08:12:43 +020016554 [ALC272_DELL] = "dell",
16555 [ALC272_DELL_ZM1] = "dell-zm1",
Chris Pockelé9541ba12009-05-12 08:08:53 +020016556 [ALC272_SAMSUNG_NC10] = "samsung-nc10",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016557 [ALC662_AUTO] = "auto",
16558};
16559
16560static struct snd_pci_quirk alc662_cfg_tbl[] = {
Takashi Iwaidea0a502009-02-09 17:14:52 +010016561 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
Kailang Yang622e84c2009-04-21 07:39:04 +020016562 SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
16563 SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016564 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
16565 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
16566 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
16567 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
16568 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
16569 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
16570 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
16571 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
16572 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
16573 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
16574 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
16575 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020016576 SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3),
16577 SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA),
16578 SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016579 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
16580 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
16581 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
16582 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020016583 SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016584 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
16585 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang6dda9f42008-05-27 12:05:31 +020016586 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016587 /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/
16588 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
16589 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020016590 SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1),
16591 SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1),
16592 SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016593 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
16594 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
16595 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020016596 SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016597 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
16598 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020016599 SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016600 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
Kailang Yang80ffe862008-10-15 11:23:27 +020016601 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016602 /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/
16603 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
16604 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020016605 SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016606 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
16607 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010016608 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020016609 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010016610 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016611 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
Herton Ronaldo Krzesinski95fe5f22008-09-26 23:48:45 -030016612 SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
16613 ALC662_3ST_6ch_DIG),
Chris Pockelé9541ba12009-05-12 08:08:53 +020016614 SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
Herton Ronaldo Krzesinskicb559742008-09-26 23:47:45 -030016615 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
16616 ALC662_3ST_6ch_DIG),
Vedran Miletic19c009a2008-09-29 20:29:25 +020016617 SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
Takashi Iwai5bd37292009-04-21 18:36:30 +020016618 SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016619 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Takashi Iwai238713d2008-10-05 10:57:39 +020016620 SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
Vedran Miletic19c009a2008-09-29 20:29:25 +020016621 ALC662_3ST_6ch_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016622 SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
16623 ALC663_ASUS_H13),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016624 {}
16625};
16626
16627static struct alc_config_preset alc662_presets[] = {
16628 [ALC662_3ST_2ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016629 .mixers = { alc662_3ST_2ch_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016630 .init_verbs = { alc662_init_verbs },
16631 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16632 .dac_nids = alc662_dac_nids,
16633 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016634 .dig_in_nid = ALC662_DIGIN_NID,
16635 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16636 .channel_mode = alc662_3ST_2ch_modes,
16637 .input_mux = &alc662_capture_source,
16638 },
16639 [ALC662_3ST_6ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016640 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016641 .init_verbs = { alc662_init_verbs },
16642 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16643 .dac_nids = alc662_dac_nids,
16644 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016645 .dig_in_nid = ALC662_DIGIN_NID,
16646 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
16647 .channel_mode = alc662_3ST_6ch_modes,
16648 .need_dac_fix = 1,
16649 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016650 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016651 [ALC662_3ST_6ch] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016652 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016653 .init_verbs = { alc662_init_verbs },
16654 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16655 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016656 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
16657 .channel_mode = alc662_3ST_6ch_modes,
16658 .need_dac_fix = 1,
16659 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016660 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016661 [ALC662_5ST_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016662 .mixers = { alc662_base_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016663 .init_verbs = { alc662_init_verbs },
16664 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16665 .dac_nids = alc662_dac_nids,
16666 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016667 .dig_in_nid = ALC662_DIGIN_NID,
16668 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
16669 .channel_mode = alc662_5stack_modes,
16670 .input_mux = &alc662_capture_source,
16671 },
16672 [ALC662_LENOVO_101E] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016673 .mixers = { alc662_lenovo_101e_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016674 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
16675 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16676 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016677 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16678 .channel_mode = alc662_3ST_2ch_modes,
16679 .input_mux = &alc662_lenovo_101e_capture_source,
16680 .unsol_event = alc662_lenovo_101e_unsol_event,
16681 .init_hook = alc662_lenovo_101e_all_automute,
16682 },
Kailang Yang291702f2007-10-16 14:28:03 +020016683 [ALC662_ASUS_EEEPC_P701] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016684 .mixers = { alc662_eeepc_p701_mixer },
Kailang Yang291702f2007-10-16 14:28:03 +020016685 .init_verbs = { alc662_init_verbs,
16686 alc662_eeepc_sue_init_verbs },
16687 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16688 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020016689 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16690 .channel_mode = alc662_3ST_2ch_modes,
16691 .input_mux = &alc662_eeepc_capture_source,
16692 .unsol_event = alc662_eeepc_unsol_event,
16693 .init_hook = alc662_eeepc_inithook,
16694 },
Kailang Yang8c427222008-01-10 13:03:59 +010016695 [ALC662_ASUS_EEEPC_EP20] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016696 .mixers = { alc662_eeepc_ep20_mixer,
Kailang Yang8c427222008-01-10 13:03:59 +010016697 alc662_chmode_mixer },
16698 .init_verbs = { alc662_init_verbs,
16699 alc662_eeepc_ep20_sue_init_verbs },
16700 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16701 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010016702 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
16703 .channel_mode = alc662_3ST_6ch_modes,
16704 .input_mux = &alc662_lenovo_101e_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020016705 .unsol_event = alc662_eeepc_unsol_event,
Kailang Yang8c427222008-01-10 13:03:59 +010016706 .init_hook = alc662_eeepc_ep20_inithook,
16707 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020016708 [ALC662_ECS] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016709 .mixers = { alc662_ecs_mixer },
Kailang Yangf1d4e282008-08-26 14:03:29 +020016710 .init_verbs = { alc662_init_verbs,
16711 alc662_ecs_init_verbs },
16712 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16713 .dac_nids = alc662_dac_nids,
16714 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16715 .channel_mode = alc662_3ST_2ch_modes,
16716 .input_mux = &alc662_eeepc_capture_source,
16717 .unsol_event = alc662_eeepc_unsol_event,
16718 .init_hook = alc662_eeepc_inithook,
16719 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016720 [ALC663_ASUS_M51VA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016721 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016722 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
16723 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16724 .dac_nids = alc662_dac_nids,
16725 .dig_out_nid = ALC662_DIGOUT_NID,
16726 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16727 .channel_mode = alc662_3ST_2ch_modes,
16728 .input_mux = &alc663_m51va_capture_source,
16729 .unsol_event = alc663_m51va_unsol_event,
16730 .init_hook = alc663_m51va_inithook,
16731 },
16732 [ALC663_ASUS_G71V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016733 .mixers = { alc663_g71v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016734 .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
16735 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16736 .dac_nids = alc662_dac_nids,
16737 .dig_out_nid = ALC662_DIGOUT_NID,
16738 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16739 .channel_mode = alc662_3ST_2ch_modes,
16740 .input_mux = &alc662_eeepc_capture_source,
16741 .unsol_event = alc663_g71v_unsol_event,
16742 .init_hook = alc663_g71v_inithook,
16743 },
16744 [ALC663_ASUS_H13] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016745 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016746 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
16747 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16748 .dac_nids = alc662_dac_nids,
16749 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16750 .channel_mode = alc662_3ST_2ch_modes,
16751 .input_mux = &alc663_m51va_capture_source,
16752 .unsol_event = alc663_m51va_unsol_event,
16753 .init_hook = alc663_m51va_inithook,
16754 },
16755 [ALC663_ASUS_G50V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016756 .mixers = { alc663_g50v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016757 .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
16758 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16759 .dac_nids = alc662_dac_nids,
16760 .dig_out_nid = ALC662_DIGOUT_NID,
16761 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
16762 .channel_mode = alc662_3ST_6ch_modes,
16763 .input_mux = &alc663_capture_source,
16764 .unsol_event = alc663_g50v_unsol_event,
16765 .init_hook = alc663_g50v_inithook,
16766 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020016767 [ALC663_ASUS_MODE1] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016768 .mixers = { alc663_m51va_mixer },
16769 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016770 .init_verbs = { alc662_init_verbs,
16771 alc663_21jd_amic_init_verbs },
16772 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16773 .hp_nid = 0x03,
16774 .dac_nids = alc662_dac_nids,
16775 .dig_out_nid = ALC662_DIGOUT_NID,
16776 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16777 .channel_mode = alc662_3ST_2ch_modes,
16778 .input_mux = &alc662_eeepc_capture_source,
16779 .unsol_event = alc663_mode1_unsol_event,
16780 .init_hook = alc663_mode1_inithook,
16781 },
16782 [ALC662_ASUS_MODE2] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016783 .mixers = { alc662_1bjd_mixer },
16784 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016785 .init_verbs = { alc662_init_verbs,
16786 alc662_1bjd_amic_init_verbs },
16787 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16788 .dac_nids = alc662_dac_nids,
16789 .dig_out_nid = ALC662_DIGOUT_NID,
16790 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16791 .channel_mode = alc662_3ST_2ch_modes,
16792 .input_mux = &alc662_eeepc_capture_source,
16793 .unsol_event = alc662_mode2_unsol_event,
16794 .init_hook = alc662_mode2_inithook,
16795 },
16796 [ALC663_ASUS_MODE3] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016797 .mixers = { alc663_two_hp_m1_mixer },
16798 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016799 .init_verbs = { alc662_init_verbs,
16800 alc663_two_hp_amic_m1_init_verbs },
16801 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16802 .hp_nid = 0x03,
16803 .dac_nids = alc662_dac_nids,
16804 .dig_out_nid = ALC662_DIGOUT_NID,
16805 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16806 .channel_mode = alc662_3ST_2ch_modes,
16807 .input_mux = &alc662_eeepc_capture_source,
16808 .unsol_event = alc663_mode3_unsol_event,
16809 .init_hook = alc663_mode3_inithook,
16810 },
16811 [ALC663_ASUS_MODE4] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016812 .mixers = { alc663_asus_21jd_clfe_mixer },
16813 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016814 .init_verbs = { alc662_init_verbs,
16815 alc663_21jd_amic_init_verbs},
16816 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16817 .hp_nid = 0x03,
16818 .dac_nids = alc662_dac_nids,
16819 .dig_out_nid = ALC662_DIGOUT_NID,
16820 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16821 .channel_mode = alc662_3ST_2ch_modes,
16822 .input_mux = &alc662_eeepc_capture_source,
16823 .unsol_event = alc663_mode4_unsol_event,
16824 .init_hook = alc663_mode4_inithook,
16825 },
16826 [ALC663_ASUS_MODE5] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016827 .mixers = { alc663_asus_15jd_clfe_mixer },
16828 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016829 .init_verbs = { alc662_init_verbs,
16830 alc663_15jd_amic_init_verbs },
16831 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16832 .hp_nid = 0x03,
16833 .dac_nids = alc662_dac_nids,
16834 .dig_out_nid = ALC662_DIGOUT_NID,
16835 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16836 .channel_mode = alc662_3ST_2ch_modes,
16837 .input_mux = &alc662_eeepc_capture_source,
16838 .unsol_event = alc663_mode5_unsol_event,
16839 .init_hook = alc663_mode5_inithook,
16840 },
16841 [ALC663_ASUS_MODE6] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016842 .mixers = { alc663_two_hp_m2_mixer },
16843 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016844 .init_verbs = { alc662_init_verbs,
16845 alc663_two_hp_amic_m2_init_verbs },
16846 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16847 .hp_nid = 0x03,
16848 .dac_nids = alc662_dac_nids,
16849 .dig_out_nid = ALC662_DIGOUT_NID,
16850 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16851 .channel_mode = alc662_3ST_2ch_modes,
16852 .input_mux = &alc662_eeepc_capture_source,
16853 .unsol_event = alc663_mode6_unsol_event,
16854 .init_hook = alc663_mode6_inithook,
16855 },
Kailang Yang622e84c2009-04-21 07:39:04 +020016856 [ALC272_DELL] = {
16857 .mixers = { alc663_m51va_mixer },
16858 .cap_mixer = alc272_auto_capture_mixer,
16859 .init_verbs = { alc662_init_verbs, alc272_dell_init_verbs },
16860 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
16861 .dac_nids = alc662_dac_nids,
16862 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16863 .adc_nids = alc272_adc_nids,
16864 .num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
16865 .capsrc_nids = alc272_capsrc_nids,
16866 .channel_mode = alc662_3ST_2ch_modes,
16867 .input_mux = &alc663_m51va_capture_source,
16868 .unsol_event = alc663_m51va_unsol_event,
16869 .init_hook = alc663_m51va_inithook,
16870 },
16871 [ALC272_DELL_ZM1] = {
16872 .mixers = { alc663_m51va_mixer },
16873 .cap_mixer = alc662_auto_capture_mixer,
16874 .init_verbs = { alc662_init_verbs, alc272_dell_zm1_init_verbs },
16875 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
16876 .dac_nids = alc662_dac_nids,
16877 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16878 .adc_nids = alc662_adc_nids,
16879 .num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
16880 .capsrc_nids = alc662_capsrc_nids,
16881 .channel_mode = alc662_3ST_2ch_modes,
16882 .input_mux = &alc663_m51va_capture_source,
16883 .unsol_event = alc663_m51va_unsol_event,
16884 .init_hook = alc663_m51va_inithook,
16885 },
Chris Pockelé9541ba12009-05-12 08:08:53 +020016886 [ALC272_SAMSUNG_NC10] = {
16887 .mixers = { alc272_nc10_mixer },
16888 .init_verbs = { alc662_init_verbs,
16889 alc663_21jd_amic_init_verbs },
16890 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
16891 .dac_nids = alc272_dac_nids,
16892 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16893 .channel_mode = alc662_3ST_2ch_modes,
16894 .input_mux = &alc272_nc10_capture_source,
16895 .unsol_event = alc663_mode4_unsol_event,
16896 .init_hook = alc663_mode4_inithook,
16897 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016898};
16899
16900
16901/*
16902 * BIOS auto configuration
16903 */
16904
16905/* add playback controls from the parsed DAC table */
16906static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
16907 const struct auto_pin_cfg *cfg)
16908{
16909 char name[32];
16910 static const char *chname[4] = {
16911 "Front", "Surround", NULL /*CLFE*/, "Side"
16912 };
16913 hda_nid_t nid;
16914 int i, err;
16915
16916 for (i = 0; i < cfg->line_outs; i++) {
16917 if (!spec->multiout.dac_nids[i])
16918 continue;
Kailang Yangb60dd392007-09-20 12:50:29 +020016919 nid = alc880_idx_to_dac(i);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016920 if (i == 2) {
16921 /* Center/LFE */
16922 err = add_control(spec, ALC_CTL_WIDGET_VOL,
16923 "Center Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016924 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
16925 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016926 if (err < 0)
16927 return err;
16928 err = add_control(spec, ALC_CTL_WIDGET_VOL,
16929 "LFE Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016930 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
16931 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016932 if (err < 0)
16933 return err;
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016934 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016935 "Center Playback Switch",
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016936 HDA_COMPOSE_AMP_VAL(0x0e, 1, 0,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016937 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016938 if (err < 0)
16939 return err;
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016940 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016941 "LFE Playback Switch",
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016942 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016943 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016944 if (err < 0)
16945 return err;
16946 } else {
16947 sprintf(name, "%s Playback Volume", chname[i]);
16948 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016949 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
16950 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016951 if (err < 0)
16952 return err;
16953 sprintf(name, "%s Playback Switch", chname[i]);
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016954 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
16955 HDA_COMPOSE_AMP_VAL(alc880_idx_to_mixer(i),
16956 3, 0, HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016957 if (err < 0)
16958 return err;
16959 }
16960 }
16961 return 0;
16962}
16963
16964/* add playback controls for speaker and HP outputs */
16965static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
16966 const char *pfx)
16967{
16968 hda_nid_t nid;
16969 int err;
16970 char name[32];
16971
16972 if (!pin)
16973 return 0;
16974
Takashi Iwai24fb9172008-09-02 14:48:20 +020016975 if (pin == 0x17) {
16976 /* ALC663 has a mono output pin on 0x17 */
16977 sprintf(name, "%s Playback Switch", pfx);
16978 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
16979 HDA_COMPOSE_AMP_VAL(pin, 2, 0, HDA_OUTPUT));
16980 return err;
16981 }
16982
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016983 if (alc880_is_fixed_pin(pin)) {
16984 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai939778a2009-02-05 15:57:55 +010016985 /* printk(KERN_DEBUG "DAC nid=%x\n",nid); */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016986 /* specify the DAC as the extra output */
16987 if (!spec->multiout.hp_nid)
16988 spec->multiout.hp_nid = nid;
16989 else
16990 spec->multiout.extra_out_nid[0] = nid;
16991 /* control HP volume/switch on the output mixer amp */
16992 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
16993 sprintf(name, "%s Playback Volume", pfx);
16994 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
16995 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
16996 if (err < 0)
16997 return err;
16998 sprintf(name, "%s Playback Switch", pfx);
16999 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
17000 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
17001 if (err < 0)
17002 return err;
17003 } else if (alc880_is_multi_pin(pin)) {
17004 /* set manual connection */
17005 /* we have only a switch on HP-out PIN */
17006 sprintf(name, "%s Playback Switch", pfx);
17007 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
17008 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
17009 if (err < 0)
17010 return err;
17011 }
17012 return 0;
17013}
17014
Takashi Iwai2d864c42009-03-20 12:52:47 +010017015/* return the index of the src widget from the connection list of the nid.
17016 * return -1 if not found
17017 */
17018static int alc662_input_pin_idx(struct hda_codec *codec, hda_nid_t nid,
17019 hda_nid_t src)
17020{
17021 hda_nid_t conn_list[HDA_MAX_CONNECTIONS];
17022 int i, conns;
17023
17024 conns = snd_hda_get_connections(codec, nid, conn_list,
17025 ARRAY_SIZE(conn_list));
17026 if (conns < 0)
17027 return -1;
17028 for (i = 0; i < conns; i++)
17029 if (conn_list[i] == src)
17030 return i;
17031 return -1;
17032}
17033
17034static int alc662_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
17035{
Takashi Iwai1327a322009-03-23 13:07:47 +010017036 unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
Takashi Iwai2d864c42009-03-20 12:52:47 +010017037 return (pincap & AC_PINCAP_IN) != 0;
17038}
17039
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017040/* create playback/capture controls for input pins */
Takashi Iwai2d864c42009-03-20 12:52:47 +010017041static int alc662_auto_create_analog_input_ctls(struct hda_codec *codec,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017042 const struct auto_pin_cfg *cfg)
17043{
Takashi Iwai2d864c42009-03-20 12:52:47 +010017044 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020017045 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017046 int i, err, idx;
17047
17048 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai2d864c42009-03-20 12:52:47 +010017049 if (alc662_is_input_pin(codec, cfg->input_pins[i])) {
17050 idx = alc662_input_pin_idx(codec, 0x0b,
17051 cfg->input_pins[i]);
17052 if (idx >= 0) {
17053 err = new_analog_input(spec, cfg->input_pins[i],
17054 auto_pin_cfg_labels[i],
17055 idx, 0x0b);
17056 if (err < 0)
17057 return err;
17058 }
17059 idx = alc662_input_pin_idx(codec, 0x22,
17060 cfg->input_pins[i]);
17061 if (idx >= 0) {
17062 imux->items[imux->num_items].label =
17063 auto_pin_cfg_labels[i];
17064 imux->items[imux->num_items].index = idx;
17065 imux->num_items++;
17066 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017067 }
17068 }
17069 return 0;
17070}
17071
17072static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
17073 hda_nid_t nid, int pin_type,
17074 int dac_idx)
17075{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017076 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017077 /* need the manual connection? */
17078 if (alc880_is_multi_pin(nid)) {
17079 struct alc_spec *spec = codec->spec;
17080 int idx = alc880_multi_pin_idx(nid);
17081 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
17082 AC_VERB_SET_CONNECT_SEL,
17083 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
17084 }
17085}
17086
17087static void alc662_auto_init_multi_out(struct hda_codec *codec)
17088{
17089 struct alc_spec *spec = codec->spec;
17090 int i;
17091
17092 for (i = 0; i <= HDA_SIDE; i++) {
17093 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020017094 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017095 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020017096 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017097 i);
17098 }
17099}
17100
17101static void alc662_auto_init_hp_out(struct hda_codec *codec)
17102{
17103 struct alc_spec *spec = codec->spec;
17104 hda_nid_t pin;
17105
17106 pin = spec->autocfg.hp_pins[0];
17107 if (pin) /* connect to front */
17108 /* use dac 0 */
17109 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017110 pin = spec->autocfg.speaker_pins[0];
17111 if (pin)
17112 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017113}
17114
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017115#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
17116
17117static void alc662_auto_init_analog_input(struct hda_codec *codec)
17118{
17119 struct alc_spec *spec = codec->spec;
17120 int i;
17121
17122 for (i = 0; i < AUTO_PIN_LAST; i++) {
17123 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai2d864c42009-03-20 12:52:47 +010017124 if (alc662_is_input_pin(codec, nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +010017125 alc_set_input_pin(codec, nid, i);
Takashi Iwai52ca15b2009-03-23 12:51:55 +010017126 if (nid != ALC662_PIN_CD_NID &&
Takashi Iwaie82c0252009-03-23 15:17:38 +010017127 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017128 snd_hda_codec_write(codec, nid, 0,
17129 AC_VERB_SET_AMP_GAIN_MUTE,
17130 AMP_OUT_MUTE);
17131 }
17132 }
17133}
17134
Takashi Iwaif511b012008-08-15 16:46:42 +020017135#define alc662_auto_init_input_src alc882_auto_init_input_src
17136
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017137static int alc662_parse_auto_config(struct hda_codec *codec)
17138{
17139 struct alc_spec *spec = codec->spec;
17140 int err;
17141 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
17142
17143 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
17144 alc662_ignore);
17145 if (err < 0)
17146 return err;
17147 if (!spec->autocfg.line_outs)
17148 return 0; /* can't find valid BIOS pin config */
17149
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017150 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
17151 if (err < 0)
17152 return err;
17153 err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg);
17154 if (err < 0)
17155 return err;
17156 err = alc662_auto_create_extra_out(spec,
17157 spec->autocfg.speaker_pins[0],
17158 "Speaker");
17159 if (err < 0)
17160 return err;
17161 err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
17162 "Headphone");
17163 if (err < 0)
17164 return err;
Takashi Iwai2d864c42009-03-20 12:52:47 +010017165 err = alc662_auto_create_analog_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017166 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017167 return err;
17168
17169 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
17170
Takashi Iwai0852d7a2009-02-11 11:35:15 +010017171 if (spec->autocfg.dig_outs)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017172 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
17173
Takashi Iwai603c4012008-07-30 15:01:44 +020017174 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010017175 add_mixer(spec, spec->kctls.list);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017176
17177 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020017178 spec->input_mux = &spec->private_imux[0];
Kailang Yangea1fb292008-08-26 12:58:38 +020017179
Takashi Iwaid88897e2008-10-31 15:01:37 +010017180 add_verb(spec, alc662_auto_init_verbs);
Takashi Iwai24fb9172008-09-02 14:48:20 +020017181 if (codec->vendor_id == 0x10ec0663)
Takashi Iwaid88897e2008-10-31 15:01:37 +010017182 add_verb(spec, alc663_auto_init_verbs);
Takashi Iwaiee979a142008-09-02 15:42:20 +020017183
17184 err = alc_auto_add_mic_boost(codec);
17185 if (err < 0)
17186 return err;
17187
Takashi Iwai4a79ba342009-04-22 16:31:35 +020017188 alc_ssid_check(codec, 0x15, 0x1b, 0x14);
17189
Takashi Iwai8c87286f2007-06-19 12:11:16 +020017190 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017191}
17192
17193/* additional initialization for auto-configuration model */
17194static void alc662_auto_init(struct hda_codec *codec)
17195{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017196 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017197 alc662_auto_init_multi_out(codec);
17198 alc662_auto_init_hp_out(codec);
17199 alc662_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020017200 alc662_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017201 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020017202 alc_inithook(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017203}
17204
17205static int patch_alc662(struct hda_codec *codec)
17206{
17207 struct alc_spec *spec;
17208 int err, board_config;
17209
17210 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
17211 if (!spec)
17212 return -ENOMEM;
17213
17214 codec->spec = spec;
17215
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020017216 alc_fix_pll_init(codec, 0x20, 0x04, 15);
17217
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017218 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
17219 alc662_models,
17220 alc662_cfg_tbl);
17221 if (board_config < 0) {
Takashi Iwai6c627f32009-05-18 12:33:36 +020017222 printk(KERN_INFO "hda_codec: Unknown model for %s, "
17223 "trying auto-probe from BIOS...\n", codec->chip_name);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017224 board_config = ALC662_AUTO;
17225 }
17226
17227 if (board_config == ALC662_AUTO) {
17228 /* automatic parse from the BIOS config */
17229 err = alc662_parse_auto_config(codec);
17230 if (err < 0) {
17231 alc_free(codec);
17232 return err;
Takashi Iwai8c87286f2007-06-19 12:11:16 +020017233 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017234 printk(KERN_INFO
17235 "hda_codec: Cannot set up configuration "
17236 "from BIOS. Using base mode...\n");
17237 board_config = ALC662_3ST_2ch_DIG;
17238 }
17239 }
17240
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090017241 err = snd_hda_attach_beep_device(codec, 0x1);
17242 if (err < 0) {
17243 alc_free(codec);
17244 return err;
17245 }
17246
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017247 if (board_config != ALC662_AUTO)
17248 setup_preset(spec, &alc662_presets[board_config]);
17249
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017250 spec->stream_analog_playback = &alc662_pcm_analog_playback;
17251 spec->stream_analog_capture = &alc662_pcm_analog_capture;
17252
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017253 spec->stream_digital_playback = &alc662_pcm_digital_playback;
17254 spec->stream_digital_capture = &alc662_pcm_digital_capture;
17255
Takashi Iwaie1406342008-02-11 18:32:32 +010017256 spec->adc_nids = alc662_adc_nids;
17257 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
17258 spec->capsrc_nids = alc662_capsrc_nids;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020017259 spec->capture_style = CAPT_MIX;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017260
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017261 if (!spec->cap_mixer)
17262 set_capture_mixer(spec);
Takashi Iwaib9591442009-03-16 15:25:00 +010017263 if (codec->vendor_id == 0x10ec0662)
17264 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
17265 else
17266 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017267
Takashi Iwai2134ea42008-01-10 16:53:55 +010017268 spec->vmaster_nid = 0x02;
17269
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017270 codec->patch_ops = alc_patch_ops;
17271 if (board_config == ALC662_AUTO)
17272 spec->init_hook = alc662_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020017273#ifdef CONFIG_SND_HDA_POWER_SAVE
17274 if (!spec->loopback.amplist)
17275 spec->loopback.amplist = alc662_loopbacks;
17276#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010017277 codec->proc_widget_hook = print_realtek_coef;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017278
17279 return 0;
17280}
17281
17282/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070017283 * patch entries
17284 */
Takashi Iwai1289e9e2008-11-27 15:47:11 +010017285static struct hda_codec_preset snd_hda_preset_realtek[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070017286 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010017287 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010017288 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020017289 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010017290 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +020017291 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017292 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017293 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017294 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
17295 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
17296 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017297 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
17298 .patch = patch_alc883 },
17299 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
17300 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020017301 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017302 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070017303 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020017304 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
Clive Messer669faba2008-09-30 15:49:13 +020017305 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
17306 .patch = patch_alc882 }, /* should be patch_alc883() in future */
Takashi Iwaicb308f92008-04-16 14:13:29 +020017307 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai7943a8a2008-04-16 17:29:09 +020017308 .patch = patch_alc882 }, /* should be patch_alc883() in future */
Kailang Yangdf694da2005-12-05 19:42:22 +010017309 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Kailang Yanga385a522008-10-15 11:20:21 +020017310 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc883 },
Kailang Yang44426082008-10-15 11:18:05 +020017311 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
17312 .patch = patch_alc883 },
Wu Fengguang3fea2cb2008-12-26 12:20:43 +080017313 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
Kailang Yangf6a92242007-12-13 16:52:54 +010017314 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070017315 {} /* terminator */
17316};
Takashi Iwai1289e9e2008-11-27 15:47:11 +010017317
17318MODULE_ALIAS("snd-hda-codec-id:10ec*");
17319
17320MODULE_LICENSE("GPL");
17321MODULE_DESCRIPTION("Realtek HD-audio codec");
17322
17323static struct hda_codec_preset_list realtek_list = {
17324 .preset = snd_hda_preset_realtek,
17325 .owner = THIS_MODULE,
17326};
17327
17328static int __init patch_realtek_init(void)
17329{
17330 return snd_hda_add_codec_preset(&realtek_list);
17331}
17332
17333static void __exit patch_realtek_exit(void)
17334{
17335 snd_hda_delete_codec_preset(&realtek_list);
17336}
17337
17338module_init(patch_realtek_init)
17339module_exit(patch_realtek_exit)